* mailbox.
*
* @param array $data The overview information for a message as returned
- * from the IMP_Mailbox::getMailboxArray() call (see
- * lib/Mailbox.php for documentation on the structure
- * of the array).
+ * from the IMP_Mailbox_List::getMailboxArray() call
+ * (see lib/Mailbox/List.php for documentation on the
+ * structure of the array).
* @param string $mode Either 'imp' or 'dimp'.
*
* @return array An array of additional flags to add. These flags must be
$result->ViewPort = $this->_viewPortData(true);
} else {
$result->ViewPort = new stdClass;
- $result->ViewPort->updatecacheid = $GLOBALS['injector']->getInstance('IMP_Mailbox')->getOb($this->_vars->view)->getCacheID($this->_vars->view);
+ $result->ViewPort->updatecacheid = $GLOBALS['injector']->getInstance('IMP_Mailbox_List')->getList($this->_vars->view)->getCacheID($this->_vars->view);
$result->ViewPort->view = $this->_vars->view;
}
return $result;
$result = $this->_checkUidvalidity($result);
} elseif (!$change) {
/* Only update cacheid info if it changed. */
- $cacheid = $GLOBALS['injector']->getInstance('IMP_Mailbox')->getOb($this->_vars->view)->getCacheID($this->_vars->view);
+ $cacheid = $GLOBALS['injector']->getInstance('IMP_Mailbox_List')->getList($this->_vars->view)->getCacheID($this->_vars->view);
if ($cacheid != $this->_vars->cacheid) {
$result->ViewPort = new stdClass;
$result->ViewPort->updatecacheid = $cacheid;
$result->ViewPort = $this->_viewPortData(true);
} else {
$result->ViewPort = new stdClass;
- $result->ViewPort->updatecacheid = $GLOBALS['injector']->getInstance('IMP_Mailbox')->getOb($this->_vars->view)->getCacheID($this->_vars->view);
+ $result->ViewPort->updatecacheid = $GLOBALS['injector']->getInstance('IMP_Mailbox_List')->getList($this->_vars->view)->getCacheID($this->_vars->view);
$result->ViewPort->view = $this->_vars->view;
}
}
}
- return ($GLOBALS['injector']->getInstance('IMP_Mailbox')->getOb($this->_vars->view)->getCacheID($this->_vars->view) != $this->_vars->cacheid);
+ return ($GLOBALS['injector']->getInstance('IMP_Mailbox_List')->getList($this->_vars->view)->getCacheID($this->_vars->view) != $this->_vars->cacheid);
}
/**
'IMP_Imap' => 'IMP_Injector_Binder_Imap',
'IMP_Imap_Tree' => 'IMP_Injector_Binder_Imaptree',
'IMP_Mail' => 'IMP_Injector_Binder_Mail',
- 'IMP_Mailbox' => 'IMP_Injector_Binder_Mailbox',
+ 'IMP_Mailbox_List' => 'IMP_Injector_Binder_MailboxList',
'IMP_Mime_Viewer' => 'IMP_Injector_Binder_MimeViewer',
'IMP_Quota' => 'IMP_Injector_Binder_Quota',
'IMP_Search' => 'IMP_Injector_Binder_Search',
* + IMP_Compose object
* + IMP_Contents object
* + IMP_Indices object
- * + IMP_Mailbox object
+ * + IMP_Mailbox_List_Track object
* + String
* Format: IMAP sequence string
*
);
} elseif ($data instanceof IMP_Indices) {
$indices = $data->indices();
- } elseif ($data instanceof IMP_Mailbox) {
+ } elseif ($data instanceof IMP_Mailbox_List_Track) {
$idx = $data->getIMAPIndex();
$indices = array(
$idx['mailbox'] => array($idx['uid'])
+++ /dev/null
-<?php
-/**
- * Binder for IMP_Mailbox::.
- *
- * Copyright 2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/gpl.html GPL
- * @package IMP
- */
-class IMP_Injector_Binder_Mailbox implements Horde_Injector_Binder
-{
- /**
- */
- public function create(Horde_Injector $injector)
- {
- return new IMP_Injector_Factory_Mailbox($injector);
- }
-
- /**
- */
- public function equals(Horde_Injector_Binder $binder)
- {
- return false;
- }
-
-}
--- /dev/null
+<?php
+/**
+ * Binder for IMP_Mailbox_List::.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/gpl.html GPL
+ * @package IMP
+ */
+class IMP_Injector_Binder_MailboxList implements Horde_Injector_Binder
+{
+ /**
+ */
+ public function create(Horde_Injector $injector)
+ {
+ return new IMP_Injector_Factory_MailboxList($injector);
+ }
+
+ /**
+ */
+ public function equals(Horde_Injector_Binder $binder)
+ {
+ return false;
+ }
+
+}
+++ /dev/null
-<?php
-/**
- * A Horde_Injector:: based IMP_Mailbox:: factory.
- *
- * PHP version 5
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/gpl.html GPL
- * @link http://pear.horde.org/index.php?package=IMP
- * @package IMP
- */
-
-/**
- * A Horde_Injector:: based IMP_Mailbox:: factory.
- *
- * Copyright 2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/gpl.html GPL
- * @link http://pear.horde.org/index.php?package=IMP
- * @package IMP
- */
-class IMP_Injector_Factory_Mailbox
-{
- /**
- * Instances.
- *
- * @var array
- */
- private $_instances = array();
-
- /**
- * The injector.
- *
- * @var Horde_Injector
- */
- private $_injector;
-
- /**
- * Constructor.
- *
- * @param Horde_Injector $injector The injector to use.
- */
- public function __construct(Horde_Injector $injector)
- {
- $this->_injector = $injector;
- }
-
- /**
- * Return the IMP_Mailbox:: instance.
- *
- * @param string $mailbox The mailbox name.
- * @param IMP_Indices $indices An indices object.
- *
- * @return IMP_Mailbox The singleton mailbox instance.
- * @throws IMP_Exception
- */
- public function getOb($mailbox, $indices = null)
- {
- if (!isset($this->_instances[$mailbox])) {
- $this->_instances[$mailbox] = new IMP_Mailbox($mailbox, $indices);
- } elseif (!is_null($indices)) {
- $this->_instances[$mailbox]->setIndex($indices);
- }
-
- return $this->_instances[$mailbox];
- }
-
-}
--- /dev/null
+<?php
+/**
+ * A Horde_Injector:: based IMP_Mailbox_List:: factory.
+ *
+ * PHP version 5
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/gpl.html GPL
+ * @link http://pear.horde.org/index.php?package=IMP
+ * @package IMP
+ */
+
+/**
+ * A Horde_Injector:: based IMP_Mailbox_List:: factory.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/gpl.html GPL
+ * @link http://pear.horde.org/index.php?package=IMP
+ * @package IMP
+ */
+class IMP_Injector_Factory_MailboxList
+{
+ /**
+ * Instances.
+ *
+ * @var array
+ */
+ private $_instances = array(
+ 'list' => array(),
+ 'track' => array()
+ );
+
+ /**
+ * The injector.
+ *
+ * @var Horde_Injector
+ */
+ private $_injector;
+
+ /**
+ * Constructor.
+ *
+ * @param Horde_Injector $injector The injector to use.
+ */
+ public function __construct(Horde_Injector $injector)
+ {
+ $this->_injector = $injector;
+
+ register_shutdown_function(array($this, 'shutdown'));
+ }
+
+ /**
+ * Return the IMP_Mailbox_List:: instance.
+ *
+ * @param string $mailbox The mailbox name.
+ *
+ * @return IMP_Mailbox_List The singleton mailbox instance.
+ * @throws IMP_Exception
+ */
+ public function getList($mailbox)
+ {
+ if (!isset($this->_instances['list'][$mailbox])) {
+ $this->_instances['list'][$mailbox] = new IMP_Mailbox_List($mailbox);
+ }
+
+ return $this->_instances['list'][$mailbox];
+ }
+
+ /**
+ * Return the IMP_Mailbox_List_Track:: instance.
+ *
+ * @param string $mailbox The mailbox name.
+ * @param IMP_Indices $indices An indices object.
+ *
+ *
+ * @return IMP_Mailbox_List_Track The singleton mailbox instance.
+ * @throws IMP_Exception
+ */
+ public function getListTrack($mailbox, $indices = null)
+ {
+ if (!isset($this->_instances['track'][$mailbox])) {
+ $ob = null;
+ if (isset($_SESSION['imp']['cache']['imp_mailbox'][$mailbox])) {
+ try {
+ $ob = @unserialize($_SESSION['imp']['cache']['imp_mailbox'][$mailbox]);
+ } catch (Exception $e) {}
+ }
+
+ if (!$ob) {
+ $ob = new IMP_Mailbox_List_Track($mailbox);
+ }
+
+ $this->_instances['track'][$mailbox] = $ob;
+ }
+
+ if (!is_null($indices)) {
+ $this->_instances['track'][$mailbox]->setIndex($indices);
+ }
+
+ return $this->_instances['track'][$mailbox];
+ }
+
+ /**
+ * Tasks to perform on shutdown.
+ */
+ public function shutdown()
+ {
+ /* Cache mailbox information if viewing in standard (IMP) message
+ * mode. Needed to keep navigation consistent when moving through the
+ * message list, and to ensure messages aren't marked as missing in
+ * search mailboxes (e.g. if search is dependent on unseen flag). */
+ foreach ($this->_instances['track'] as $key => $val) {
+ if ($val->changed) {
+ $_SESSION['imp']['cache']['imp_mailbox'][$key] = serialize($val);
+ }
+ }
+ }
+
+}
+++ /dev/null
-<?php
-/**
- * The IMP_Mailbox:: class contains all code related to handling a mailbox
- * message list.
- *
- * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (GPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
- *
- * @author Michael Slusarz <slusarz@horde.org>
- * @category Horde
- * @license http://www.fsf.org/copyleft/gpl.html GPL
- * @package IMP
- */
-class IMP_Mailbox implements Countable
-{
- /**
- * The mailbox to work with.
- *
- * @var string
- */
- protected $_mailbox;
-
- /**
- * The location in the sorted array we are at.
- *
- * @var integer
- */
- protected $_arrayIndex = null;
-
- /**
- * The array of sorted indices.
- *
- * @var array
- */
- protected $_sorted = null;
-
- /**
- * The mailboxes corresponding to the sorted indices list.
- * If empty, uses $_mailbox.
- *
- * @var array
- */
- protected $_sortedMbox = array();
-
- /**
- * Is this a search malbox?
- *
- * @var boolean
- */
- protected $_searchmbox;
-
- /**
- * The Horde_Imap_Client_Thread object for the mailbox.
- *
- * @var Horde_Imap_Client_Thread
- */
- protected $_threadob = null;
-
- /**
- * Has the internal message list changed?
- *
- * @var boolean
- */
- protected $_changed = false;
-
- /**
- * Constructor.
- *
- * @param string $mailbox The mailbox to work with.
- * @param IMP_Indices $indices An indices object.
- */
- public function __construct($mailbox, $indices = null)
- {
- $this->_mailbox = $mailbox;
- $this->_searchmbox = $GLOBALS['injector']->getInstance('IMP_Search')->isSearchMbox($mailbox);
-
- if (is_null($indices)) {
- unset($_SESSION['imp']['cache']['imp_mailbox'][$mailbox]);
- } else {
- /* Try to rebuild sorted information from the session cache. */
- if (isset($_SESSION['imp']['cache']['imp_mailbox'][$mailbox])) {
- $tmp = json_decode($_SESSION['imp']['cache']['imp_mailbox'][$mailbox]);
- $this->_sorted = $this->_searchmbox ? $tmp->s : $tmp;
- $this->_sortedMbox = $this->_searchmbox ? $tmp->m : array();
- }
- $this->setIndex($indices);
- }
-
- register_shutdown_function(array($this, 'shutdown'));
- }
-
- /**
- * Cache mailbox information if viewing in standard (IMP) message mode.
- * Needed to keep navigation consistent when moving through the message
- * list, and to ensure messages aren't marked as missing in search
- * mailboxes (e.g. if search is dependent on unseen flag).
- */
- public function shutdown()
- {
- if ($this->_changed &&
- ($_SESSION['imp']['view'] == 'imp')) {
- /* Casting $_sorted to integers saves a significant amount of
- * space when json_encoding (no need to quote every value). Only
- * can do for IMAP though (since POP3 UIDs are not limited to
- * integers). */
- $sorted = ($_SESSION['imp']['protocol'] == 'pop')
- ? $this->_sorted
- : array_map('intval', $this->_sorted);
- $_SESSION['imp']['cache']['imp_mailbox'][$this->_mailbox] = $this->_searchmbox
- ? json_encode(array('m' => $this->_sortedMbox, 's' => $sorted))
- : json_encode($sorted);
- }
- }
-
- /**
- * Build the array of message information.
- *
- * @param array $msgnum An array of message sequence numbers.
- * @param array $options Additional options:
- * <pre>
- * 'headers' - (boolean) Return info on the non-envelope headers
- * 'Importance', 'List-Post', and 'X-Priority'.
- * DEFAULT: false (only envelope headers returned)
- * 'preview' - (mixed) Include preview information? If empty, add no
- * preview information. If 1, uses value from prefs.
- * If 2, forces addition of preview info.
- * DEFAULT: No preview information.
- * 'structure' - (boolean) Get structure information from server.
- * Contained in the 'strucutre' entry.
- * DEFAULT: false
- * </pre>
- *
- * @return array An array with the following keys:
- * <pre>
- * 'overview' - (array) The overview information. Contains the following:
- * 'envelope' - (array) Envelope information returned from
- * the IMAP server. See
- * Horde_Imap_Client::fetch() for format.
- * 'flags' - (array) The list of IMAP flags returned from
- * the server. See Horde_Imap_Client::fetch() for
- * the format.
- * 'headers' - (array) Any headers requested in
- * $options['headers']. Horde_Mime_Headers objects
- * are returned. See Horde_Imap_Client::fetch()
- * for the format.
- * 'mailbox' - (string) The mailbox containing the message.
- * 'preview' - (string) If requested in $options['preview'],
- * the preview text.
- * 'previewcut'- (boolean) Has the preview text been cut?
- * 'size' - (integer) The size of the message in bytes.
- * 'structure'- (array) The structure of the message. Only
- * set if $options['structure'] is true. See
- * Horde_Imap_Client::fetch() for format.
- * 'uid' - (string) The unique ID of the message.
- *
- * 'uids' - (IMP_Indices) An indices object.
- * </pre>
- */
- public function getMailboxArray($msgnum, $options = array())
- {
- $this->_buildMailbox();
-
- $overview = $to_process = $uids = array();
-
- /* Build the list of mailboxes and messages. */
- foreach ($msgnum as $i) {
- /* Make sure that the index is actually in the slice of messages
- we're looking at. If we're hiding deleted messages, for
- example, there may be gaps here. */
- if (isset($this->_sorted[$i - 1])) {
- $mboxname = ($this->_searchmbox) ? $this->_sortedMbox[$i - 1] : $this->_mailbox;
-
- // $uids - KEY: UID, VALUE: sequence number
- $to_process[$mboxname][$this->_sorted[$i - 1]] = $i;
- }
- }
-
- $fetch_criteria = array(
- Horde_Imap_Client::FETCH_ENVELOPE => true,
- Horde_Imap_Client::FETCH_FLAGS => true,
- Horde_Imap_Client::FETCH_SIZE => true,
- Horde_Imap_Client::FETCH_UID => true,
- );
-
- if (!empty($options['headers'])) {
- $fetch_criteria[Horde_Imap_Client::FETCH_HEADERS] = array(array('cache' => true, 'headers' => array('importance', 'list-post', 'x-priority'), 'label' => 'imp', 'parse' => true, 'peek' => true));
- }
-
- if (!empty($options['structure'])) {
- $fetch_criteria[Horde_Imap_Client::FETCH_STRUCTURE] = array('parse' => true);
- }
-
- $imp_imap = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb();
-
- if (empty($options['preview'])) {
- $cache = null;
- $options['preview'] = 0;
- } else {
- $cache = $imp_imap->getCache();
- }
-
- /* Retrieve information from each mailbox. */
- foreach ($to_process as $mbox => $ids) {
- try {
- $fetch_res = $imp_imap->fetch($mbox, $fetch_criteria, array('ids' => array_keys($ids)));
-
- if ($options['preview']) {
- $preview_info = $tostore = array();
- if ($cache) {
- try {
- $preview_info = $cache->get($mbox, array_keys($ids), array('IMPpreview', 'IMPpreviewc'));
- } catch (Horde_Imap_Client_Exception $e) {}
- }
- }
-
- foreach (array_keys($ids) as $k) {
- $v = $fetch_res[$k];
-
- $v['mailbox'] = $mbox;
- if (isset($v['headers']['imp'])) {
- $v['headers'] = $v['headers']['imp'];
- }
-
- if (($options['preview'] === 2) ||
- (($options['preview'] === 1) &&
- (!$GLOBALS['prefs']->getValue('preview_show_unread') ||
- !in_array('\\seen', $v['flags'])))) {
- if (empty($preview_info[$k])) {
- try {
- $imp_contents = $GLOBALS['injector']->getInstance('IMP_Contents')->getOb(new IMP_Indices($mbox, $k));
- $prev = $imp_contents->generatePreview();
- $preview_info[$k] = array('IMPpreview' => $prev['text'], 'IMPpreviewc' => $prev['cut']);
- if (!is_null($cache)) {
- $tostore[$k] = $preview_info[$k];
- }
- } catch (Exception $e) {
- $preview_info[$k] = array('IMPpreview' => '', 'IMPpreviewc' => false);
- }
- }
-
- $v['preview'] = $preview_info[$k]['IMPpreview'];
- $v['previewcut'] = $preview_info[$k]['IMPpreviewc'];
- }
-
- $overview[] = $v;
- }
-
- $uids[$mbox] = array_keys($fetch_res);
-
- if (!is_null($cache) && !empty($tostore)) {
- $status = $imp_imap->status($mbox, Horde_Imap_Client::STATUS_UIDVALIDITY);
- $cache->set($mbox, $tostore, $status['uidvalidity']);
- }
- } catch (Horde_Imap_Client_Exception $e) {}
- }
-
- return array(
- 'overview' => $overview,
- 'uids' => new IMP_Indices($uids)
- );
- }
-
- /**
- * Returns true if the mailbox data has been built.
- *
- * @return boolean True if the mailbox has been built.
- */
- public function isBuilt()
- {
- return !is_null($this->_sorted);
- }
-
- /**
- * Builds the sorted list of messages in the mailbox.
- */
- protected function _buildMailbox()
- {
- if ($this->isBuilt()) {
- return;
- }
-
- $this->_changed = true;
- $this->_sorted = $this->_sortedMbox = array();
- $query = null;
-
- if ($this->_searchmbox) {
- if (IMP::hideDeletedMsgs($this->_mailbox)) {
- $query = new Horde_Imap_Client_Search_Query();
- $query->flag('\\deleted', false);
- }
-
- try {
- foreach ($GLOBALS['injector']->getInstance('IMP_Search')->runSearch($query, $this->_mailbox) as $mbox => $idx) {
- $this->_sorted[] = $idx;
- $this->_sortedMbox[] = $mbox;
- }
- } catch (Horde_Imap_Client_Exception $e) {
- $GLOBALS['notification']->push(_("Mailbox listing failed") . ': ' . $e->getMessage(), 'horde.error');
- }
- } else {
- $sortpref = IMP::getSort($this->_mailbox, true);
- if ($sortpref['by'] == Horde_Imap_Client::SORT_THREAD) {
- $this->_threadob = null;
- $threadob = $this->getThreadOb();
- $this->_sorted = $threadob->messageList((bool)$sortpref['dir']);
- } else {
- if (($_SESSION['imp']['protocol'] != 'pop') &&
- IMP::hideDeletedMsgs($this->_mailbox)) {
- $query = new Horde_Imap_Client_Search_Query();
- $query->flag('\\deleted', false);
- }
- try {
- $res = $GLOBALS['injector']->getInstance('IMP_Search')->imapSearch($this->_mailbox, $query, array('sort' => array($sortpref['by']), 'reverse' => (bool)$sortpref['dir']));
- $this->_sorted = $res['sort'];
- } catch (Horde_Imap_Client_Exception $e) {
- $GLOBALS['notification']->push(_("Mailbox listing failed") . ': ' . $e->getMessage(), 'horde.error');
- }
- }
- }
- }
-
- /**
- * Get the list of new messages in the mailbox (IMAP RECENT flag, with
- * UNDELETED if we're hiding deleted messages).
- *
- * @param integer $results A Horde_Imap_Client::SORT_* constant that
- * indicates the desired return type.
- * @param boolean $uid Return UIDs instead of sequence numbers (for
- * $results queries that return message lists).
- *
- * @return mixed Whatever is requested in $results.
- */
- public function newMessages($results, $uid = false)
- {
- return $this->_msgFlagSearch('recent', $results, $uid);
- }
-
- /**
- * Get the list of unseen messages in the mailbox (IMAP UNSEEN flag, with
- * UNDELETED if we're hiding deleted messages).
- *
- * @param integer $results A Horde_Imap_Client::SORT_RESULTS_* constant
- * that indicates the desired return type.
- * @param boolean $uid Return UIDs instead of sequence numbers (for
- * $results queries that return message lists).
- *
- * @return mixed Whatever is requested in $results.
- */
- public function unseenMessages($results, $uid = false)
- {
- return $this->_msgFlagSearch('unseen', $results, $uid);
- }
-
- /**
- * Do a search on a mailbox in the most efficient way available.
- *
- * @param string $type The search type - either 'recent' or 'unseen'.
- * @param integer $results A Horde_Imap_Client::SORT_RESULTS_* constant
- * that indicates the desired return type.
- * @param boolean $uid Return UIDs instead of sequence numbers (for
- * $results queries that return message lists).
- *
- * @return mixed Whatever is requested in $results.
- */
- protected function _msgFlagSearch($type, $results, $uid)
- {
- $count = ($results == Horde_Imap_Client::SORT_RESULTS_COUNT);
-
- if ($this->_searchmbox || empty($this->_sorted)) {
- if ($count &&
- $this->_searchmbox &&
- ($type == 'unseen') &&
- $GLOBALS['injector']->getInstance('IMP_Search')->isVinbox($this->_mailbox)) {
- return count($this);
- }
-
- return $count ? 0 : array();
- }
-
- $criteria = new Horde_Imap_Client_Search_Query();
- $imp_imap = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb();
-
- if (IMP::hideDeletedMsgs($this->_mailbox)) {
- $criteria->flag('\\deleted', false);
- } elseif ($count) {
- try {
- $status_res = $imp_imap->status($this->_mailbox, $type == 'recent' ? Horde_Imap_Client::STATUS_RECENT : Horde_Imap_Client::STATUS_UNSEEN);
- return $status_res[$type];
- } catch (Horde_Imap_Client_Exception $e) {
- return 0;
- }
- }
-
- if ($type == 'recent') {
- $criteria->flag('\\recent', true);
- } else {
- $criteria->flag('\\seen', false);
- }
-
- try {
- $res = $imp_imap->search($this->_mailbox, $criteria, array('results' => array($results), 'sequence' => !$uid));
- return $count ? $res['count'] : $res;
- } catch (Horde_Imap_Client_Exception $e) {
- return $count ? 0 : array();
- }
- }
-
- /**
- * Returns the current message array index. If the array index has
- * run off the end of the message array, will return the last index.
- *
- * @return integer The message array index.
- */
- public function getMessageIndex()
- {
- return is_null($this->_arrayIndex) ? 1 : $this->_arrayIndex + 1;
- }
-
- /**
- * Checks to see if the current index is valid.
- * This function is only useful if an index was passed to the constructor.
- *
- * @return boolean True if index is valid, false if not.
- */
- public function isValidIndex($rebuild = true)
- {
- return !is_null($this->_arrayIndex);
- }
-
- /**
- * Returns IMAP mbox/UID information on a message.
- *
- * @param integer $offset The offset from the current message.
- *
- * @return array Array with the following entries:
- * <pre>
- * 'mailbox' - (string) The mailbox.
- * 'uid' - (integer) The message UID.
- * </pre>
- */
- public function getIMAPIndex($offset = 0)
- {
- $index = $this->_arrayIndex + $offset;
-
- return isset($this->_sorted[$index])
- ? array(
- 'mailbox' => ($this->_searchmbox ? $this->_sortedMbox[$index] : $this->_mailbox),
- 'uid' => $this->_sorted[$index]
- )
- : array();
- }
-
- /**
- * Using the preferences and the current mailbox, determines the messages
- * to view on the current page.
- *
- * @param integer $page The page number currently being displayed.
- * @param integer $start The starting message number.
- *
- * @return array An array with the following fields:
- * <pre>
- * 'anymsg' - (boolean) Are there any messages at all in mailbox? E.g. If
- * 'msgcount' is 0, there may still be hidden deleted messages.
- * 'begin' - (integer) The beginning message sequence number of the page.
- * 'end' - (integer) The ending message sequence number of the page.
- * 'index' - (integer) The index of the starting message.
- * 'msgcount' - (integer) The number of viewable messages in the current
- * mailbox.
- * 'page' - (integer) The current page number.
- * 'pagecount' - (integer) The number of pages in this mailbox.
- * </pre>
- */
- public function buildMailboxPage($page = 0, $start = 0, $opts = array())
- {
- $this->_buildMailbox();
-
- $ret = array('msgcount' => count($this->_sorted));
-
- $page_size = $GLOBALS['prefs']->getValue('max_msgs');
-
- if ($ret['msgcount'] > $page_size) {
- $ret['pagecount'] = ceil($ret['msgcount'] / $page_size);
-
- /* Determine which page to display. */
- if (empty($page) || strcspn($page, '0123456789')) {
- if (!empty($start)) {
- /* Messages set this when returning to a mailbox. */
- $page = ceil($start / $page_size);
- } else {
- /* Search for the last visited page first. */
- if (isset($_SESSION['imp']['cache']['mbox_page'][$this->_mailbox])) {
- $page = $_SESSION['imp']['cache']['mbox_page'][$this->_mailbox];
- } elseif ($this->_searchmbox) {
- $page = 1;
- } else {
- $page = ceil($this->mailboxStart($ret['msgcount']) / $page_size);
- }
- }
- }
-
- /* Make sure we're not past the end or before the beginning, and
- that we have an integer value. */
- $ret['page'] = intval($page);
- if ($ret['page'] > $ret['pagecount']) {
- $ret['page'] = $ret['pagecount'];
- } elseif ($ret['page'] < 1) {
- $ret['page'] = 1;
- }
-
- $ret['begin'] = (($ret['page'] - 1) * $page_size) + 1;
- $ret['end'] = $ret['begin'] + $page_size - 1;
- if ($ret['end'] > $ret['msgcount']) {
- $ret['end'] = $ret['msgcount'];
- }
- } else {
- $ret['begin'] = 1;
- $ret['end'] = $ret['msgcount'];
- $ret['page'] = 1;
- $ret['pagecount'] = 1;
- }
-
- $ret['index'] = ($this->_searchmbox) ? ($ret['begin'] - 1) : $this->_arrayIndex;
-
- /* If there are no viewable messages, check for deleted messages in
- the mailbox. */
- $ret['anymsg'] = true;
- if (!$ret['msgcount'] && !$this->_searchmbox) {
- try {
- $status = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->status($this->_mailbox, Horde_Imap_Client::STATUS_MESSAGES);
- $ret['anymsg'] = (bool)$status['messages'];
- } catch (Horde_Imap_Client_Exception $e) {
- $ret['anymsg'] = false;
- }
- }
-
- /* Store the page value now. */
- $_SESSION['imp']['cache']['mbox_page'][$this->_mailbox] = $ret['page'];
-
- return $ret;
- }
-
- /**
- * Determines the sequence number of the first message to display, based
- * on the user's preferences.
- *
- * @param integer $total The total number of messages in the mailbox.
- *
- * @return integer The sequence number in the sorted mailbox.
- */
- public function mailboxStart($total)
- {
- if ($this->_searchmbox) {
- return 1;
- }
-
- switch ($GLOBALS['prefs']->getValue('mailbox_start')) {
- case IMP::MAILBOX_START_FIRSTPAGE:
- return 1;
-
- case IMP::MAILBOX_START_LASTPAGE:
- return $total;
-
- case IMP::MAILBOX_START_FIRSTUNSEEN:
- $sortpref = IMP::getSort($this->_mailbox);
-
- /* Optimization: if sorting by sequence then first unseen
- * information is returned via a SELECT/EXAMINE call. */
- if ($sortpref['by'] == Horde_Imap_Client::SORT_SEQUENCE) {
- try {
- $res = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->status($this->_mailbox, Horde_Imap_Client::STATUS_FIRSTUNSEEN);
- if (!is_null($res['firstunseen'])) {
- return $res['firstunseen'];
- }
- } catch (Horde_Imap_Client_Exception $e) {}
-
- return 1;
- }
-
- $unseen_msgs = $this->unseenMessages(Horde_Imap_Client::SORT_RESULTS_MIN, true);
- return empty($unseen_msgs['min'])
- ? 1
- : ($this->getArrayIndex($unseen_msgs['min']) + 1);
-
- case IMP::MAILBOX_START_LASTUNSEEN:
- $unseen_msgs = $this->unseenMessages(Horde_Imap_Client::SORT_RESULTS_MAX, true);
- return empty($unseen_msgs['max'])
- ? 1
- : ($this->getArrayIndex($unseen_msgs['max']) + 1);
- }
- }
-
- /**
- * Updates the message array index.
- *
- * @param mixed $data If an integer, the number of messages to increase
- * array index by. If an indices object, sets array
- * index to the index value.
- */
- public function setIndex($data)
- {
- if ($data instanceof IMP_Indices) {
- list($mailbox, $uid) = $data->getSingle();
- $this->_arrayIndex = $this->getArrayIndex($uid, $mailbox);
- if (empty($this->_arrayIndex)) {
- $this->_rebuild(true);
- $this->_arrayIndex = $this->getArrayIndex($uid, $mailbox);
- }
- } elseif (!is_null($this->_arrayIndex)) {
- $index = $this->_arrayIndex += $data;
- if (isset($this->_sorted[$this->_arrayIndex])) {
- $this->_rebuild();
- } else {
- $this->_rebuild(true);
- $this->_arrayIndex = isset($this->_sorted[$index])
- ? $index
- : null;
- }
- }
- }
-
- /**
- * Get the Horde_Imap_Client_Thread object for the current mailbox.
- *
- * @return Horde_Imap_Client_Thread The thread object for the current
- * mailbox.
- */
- public function getThreadOb()
- {
- if (is_null($this->_threadob)) {
- try {
- $this->_threadob = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->thread($this->_mailbox, array('criteria' => $_SESSION['imp']['imap']['thread']));
- } catch (Horde_Imap_Client_Exception $e) {
- $GLOBALS['notification']->push($e);
- return new Horde_Imap_Client_Thread(array(), 'uid');
- }
- }
-
- return $this->_threadob;
- }
-
- /**
- * Determines if a rebuild is needed, and, if necessary, performs
- * the rebuild.
- *
- * @param boolean $force Force a rebuild?
- */
- protected function _rebuild($force = false)
- {
- if ($force ||
- (!is_null($this->_arrayIndex) && !$this->getIMAPIndex(1))) {
- $this->_sorted = null;
- $this->_buildMailbox();
- }
- }
-
- /**
- * Returns the array index of the given message UID.
- *
- * @param integer $uid The message UID.
- * @param integer $mbox The message mailbox (defaults to the current
- * mailbox).
- *
- * @return mixed The array index of the location of the message UID in
- * the current mailbox. Returns null if not found.
- */
- public function getArrayIndex($uid, $mbox = null)
- {
- $aindex = null;
-
- $this->_buildMailbox();
-
- if ($this->_searchmbox) {
- if (is_null($mbox)) {
- $mbox = IMP::$thismailbox;
- }
-
- /* Need to compare both mbox name and message UID to obtain the
- * correct array index since there may be duplicate UIDs. */
- foreach (array_keys($this->_sorted, $uid) as $key) {
- if ($this->_sortedMbox[$key] == $mbox) {
- return $key;
- }
- }
- } else {
- /* array_search() returns false on no result. We will set an
- * unsuccessful result to NULL. */
- if (($aindex = array_search($uid, $this->_sorted)) === false) {
- $aindex = null;
- }
- }
-
- return $aindex;
- }
-
- /**
- * Returns a raw sorted list of the mailbox.
- *
- * @return array An array with two keys: 's' = sorted UIDS list, 'm' =
- * sorted mailboxes list.
- */
- public function getSortedList()
- {
- $this->_buildMailbox();
-
- /* For exterior use, the array needs to begin numbering at 1. */
- $s = $this->_sorted;
- array_unshift($s, 0);
- unset($s[0]);
- $m = $this->_sortedMbox;
- array_unshift($m, 0);
- unset($m[0]);
-
- return array('s' => $s, 'm' => $m);
- }
-
- /**
- * Returns the current sorted array without the given messages.
- *
- * @param mixed $indices An IMP_Indices object or true to remove all
- * messages in the mailbox.
- */
- public function removeMsgs($indices)
- {
- if ($indices === true) {
- $this->_rebuild(true);
- return;
- }
-
- if (!count($indices)) {
- return;
- }
-
- /* Remove the current entry and recalculate the range. */
- foreach ($indices as $mbox => $uid) {
- $val = $this->getArrayIndex($uid, $mbox);
- unset($this->_sorted[$val]);
- if ($this->_searchmbox) {
- unset($this->_sortedMbox[$val]);
- }
- }
-
- $this->_sorted = array_values($this->_sorted);
- $this->_changed = true;
- if ($this->_searchmbox) {
- $this->_sortedMbox = array_values($this->_sortedMbox);
- }
-
- $this->_threadob = null;
-
- /* Update the current array index to its new position in the message
- * array. */
- $this->setIndex(0);
- }
-
- /**
- * Returns a unique identifier for the current mailbox status.
- *
- * This cache ID is guaranteed to change if messages are added/deleted from
- * the mailbox. Additionally, if CONDSTORE is available on the remote
- * IMAP server, this ID will change if flag information changes.
- *
- * @return string The cache ID string, which will change when the
- * composition of the mailbox changes.
- */
- public function getCacheID()
- {
- if (!$this->_searchmbox) {
- $sortpref = IMP::getSort($this->_mailbox, true);
- try {
- return $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->getCacheId($this->_mailbox, array($sortpref['by'], $sortpref['dir']));
- } catch (Horde_Imap_Client_Exception $e) {}
- }
-
- return strval(new Horde_Support_Randomid());
- }
-
- /* Countable methods. */
-
- /**
- * Returns the current message count of the mailbox.
- *
- * @return integer The mailbox message count.
- */
- public function count()
- {
- $this->_buildMailbox();
- return count($this->_sorted);
- }
-
-}
--- /dev/null
+<?php
+/**
+ * This class contains code related to generating and handling a mailbox
+ * message list.
+ *
+ * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/gpl.html GPL
+ * @package IMP
+ */
+class IMP_Mailbox_List implements Countable, Serializable
+{
+ /* Serialized version. */
+ const VERSION = 1;
+
+ /**
+ * Has the internal message list changed?
+ *
+ * @var boolean
+ */
+ public $changed = false;
+
+ /**
+ * The mailbox to work with.
+ *
+ * @var string
+ */
+ protected $_mailbox;
+
+ /**
+ * Is this a search malbox?
+ *
+ * @var boolean
+ */
+ protected $_searchmbox;
+
+ /**
+ * The list of additional variables to serialize.
+ *
+ * @var array
+ */
+ protected $_slist = array();
+
+ /**
+ * The array of sorted indices.
+ *
+ * @var array
+ */
+ protected $_sorted = null;
+
+ /**
+ * The mailboxes corresponding to the sorted indices list.
+ * If empty, uses $_mailbox.
+ *
+ * @var array
+ */
+ protected $_sortedMbox = array();
+
+ /**
+ * The Horde_Imap_Client_Thread object for the mailbox.
+ *
+ * @var Horde_Imap_Client_Thread
+ */
+ protected $_threadob = null;
+
+ /**
+ * Constructor.
+ *
+ * @param string $mailbox The mailbox to work with.
+ */
+ public function __construct($mailbox)
+ {
+ $this->_mailbox = $mailbox;
+ $this->_searchmbox = $GLOBALS['injector']->getInstance('IMP_Search')->isSearchMbox($mailbox);
+ }
+
+ /**
+ * Build the array of message information.
+ *
+ * @param array $msgnum An array of message sequence numbers.
+ * @param array $options Additional options:
+ * <pre>
+ * 'headers' - (boolean) Return info on the non-envelope headers
+ * 'Importance', 'List-Post', and 'X-Priority'.
+ * DEFAULT: false (only envelope headers returned)
+ * 'preview' - (mixed) Include preview information? If empty, add no
+ * preview information. If 1, uses value from prefs.
+ * If 2, forces addition of preview info.
+ * DEFAULT: No preview information.
+ * 'structure' - (boolean) Get structure information from server.
+ * Contained in the 'strucutre' entry.
+ * DEFAULT: false
+ * </pre>
+ *
+ * @return array An array with the following keys:
+ * <pre>
+ * 'overview' - (array) The overview information. Contains the following:
+ * 'envelope' - (array) Envelope information returned from
+ * the IMAP server. See
+ * Horde_Imap_Client::fetch() for format.
+ * 'flags' - (array) The list of IMAP flags returned from
+ * the server. See Horde_Imap_Client::fetch() for
+ * the format.
+ * 'headers' - (array) Any headers requested in
+ * $options['headers']. Horde_Mime_Headers objects
+ * are returned. See Horde_Imap_Client::fetch()
+ * for the format.
+ * 'mailbox' - (string) The mailbox containing the message.
+ * 'preview' - (string) If requested in $options['preview'],
+ * the preview text.
+ * 'previewcut'- (boolean) Has the preview text been cut?
+ * 'size' - (integer) The size of the message in bytes.
+ * 'structure'- (array) The structure of the message. Only
+ * set if $options['structure'] is true. See
+ * Horde_Imap_Client::fetch() for format.
+ * 'uid' - (string) The unique ID of the message.
+ *
+ * 'uids' - (IMP_Indices) An indices object.
+ * </pre>
+ */
+ public function getMailboxArray($msgnum, $options = array())
+ {
+ $this->_buildMailbox();
+
+ $overview = $to_process = $uids = array();
+
+ /* Build the list of mailboxes and messages. */
+ foreach ($msgnum as $i) {
+ /* Make sure that the index is actually in the slice of messages
+ we're looking at. If we're hiding deleted messages, for
+ example, there may be gaps here. */
+ if (isset($this->_sorted[$i - 1])) {
+ $mboxname = ($this->_searchmbox) ? $this->_sortedMbox[$i - 1] : $this->_mailbox;
+
+ // $uids - KEY: UID, VALUE: sequence number
+ $to_process[$mboxname][$this->_sorted[$i - 1]] = $i;
+ }
+ }
+
+ $fetch_criteria = array(
+ Horde_Imap_Client::FETCH_ENVELOPE => true,
+ Horde_Imap_Client::FETCH_FLAGS => true,
+ Horde_Imap_Client::FETCH_SIZE => true,
+ Horde_Imap_Client::FETCH_UID => true,
+ );
+
+ if (!empty($options['headers'])) {
+ $fetch_criteria[Horde_Imap_Client::FETCH_HEADERS] = array(array('cache' => true, 'headers' => array('importance', 'list-post', 'x-priority'), 'label' => 'imp', 'parse' => true, 'peek' => true));
+ }
+
+ if (!empty($options['structure'])) {
+ $fetch_criteria[Horde_Imap_Client::FETCH_STRUCTURE] = array('parse' => true);
+ }
+
+ $imp_imap = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb();
+
+ if (empty($options['preview'])) {
+ $cache = null;
+ $options['preview'] = 0;
+ } else {
+ $cache = $imp_imap->getCache();
+ }
+
+ /* Retrieve information from each mailbox. */
+ foreach ($to_process as $mbox => $ids) {
+ try {
+ $fetch_res = $imp_imap->fetch($mbox, $fetch_criteria, array('ids' => array_keys($ids)));
+
+ if ($options['preview']) {
+ $preview_info = $tostore = array();
+ if ($cache) {
+ try {
+ $preview_info = $cache->get($mbox, array_keys($ids), array('IMPpreview', 'IMPpreviewc'));
+ } catch (Horde_Imap_Client_Exception $e) {}
+ }
+ }
+
+ foreach (array_keys($ids) as $k) {
+ $v = $fetch_res[$k];
+
+ $v['mailbox'] = $mbox;
+ if (isset($v['headers']['imp'])) {
+ $v['headers'] = $v['headers']['imp'];
+ }
+
+ if (($options['preview'] === 2) ||
+ (($options['preview'] === 1) &&
+ (!$GLOBALS['prefs']->getValue('preview_show_unread') ||
+ !in_array('\\seen', $v['flags'])))) {
+ if (empty($preview_info[$k])) {
+ try {
+ $imp_contents = $GLOBALS['injector']->getInstance('IMP_Contents')->getOb(new IMP_Indices($mbox, $k));
+ $prev = $imp_contents->generatePreview();
+ $preview_info[$k] = array('IMPpreview' => $prev['text'], 'IMPpreviewc' => $prev['cut']);
+ if (!is_null($cache)) {
+ $tostore[$k] = $preview_info[$k];
+ }
+ } catch (Exception $e) {
+ $preview_info[$k] = array('IMPpreview' => '', 'IMPpreviewc' => false);
+ }
+ }
+
+ $v['preview'] = $preview_info[$k]['IMPpreview'];
+ $v['previewcut'] = $preview_info[$k]['IMPpreviewc'];
+ }
+
+ $overview[] = $v;
+ }
+
+ $uids[$mbox] = array_keys($fetch_res);
+
+ if (!is_null($cache) && !empty($tostore)) {
+ $status = $imp_imap->status($mbox, Horde_Imap_Client::STATUS_UIDVALIDITY);
+ $cache->set($mbox, $tostore, $status['uidvalidity']);
+ }
+ } catch (Horde_Imap_Client_Exception $e) {}
+ }
+
+ return array(
+ 'overview' => $overview,
+ 'uids' => new IMP_Indices($uids)
+ );
+ }
+
+ /**
+ * Returns true if the mailbox data has been built.
+ *
+ * @return boolean True if the mailbox has been built.
+ */
+ public function isBuilt()
+ {
+ return !is_null($this->_sorted);
+ }
+
+ /**
+ * Builds the sorted list of messages in the mailbox.
+ */
+ protected function _buildMailbox()
+ {
+ if ($this->isBuilt()) {
+ return;
+ }
+
+ $this->changed = true;
+ $this->_sorted = $this->_sortedMbox = array();
+ $query = null;
+
+ if ($this->_searchmbox) {
+ if (IMP::hideDeletedMsgs($this->_mailbox)) {
+ $query = new Horde_Imap_Client_Search_Query();
+ $query->flag('\\deleted', false);
+ }
+
+ try {
+ foreach ($GLOBALS['injector']->getInstance('IMP_Search')->runSearch($query, $this->_mailbox) as $mbox => $idx) {
+ $this->_sorted[] = $idx;
+ $this->_sortedMbox[] = $mbox;
+ }
+ } catch (Horde_Imap_Client_Exception $e) {
+ $GLOBALS['notification']->push(_("Mailbox listing failed") . ': ' . $e->getMessage(), 'horde.error');
+ }
+ } else {
+ $sortpref = IMP::getSort($this->_mailbox, true);
+ if ($sortpref['by'] == Horde_Imap_Client::SORT_THREAD) {
+ $this->_threadob = null;
+ $threadob = $this->getThreadOb();
+ $this->_sorted = $threadob->messageList((bool)$sortpref['dir']);
+ } else {
+ if (($_SESSION['imp']['protocol'] != 'pop') &&
+ IMP::hideDeletedMsgs($this->_mailbox)) {
+ $query = new Horde_Imap_Client_Search_Query();
+ $query->flag('\\deleted', false);
+ }
+ try {
+ $res = $GLOBALS['injector']->getInstance('IMP_Search')->imapSearch($this->_mailbox, $query, array('sort' => array($sortpref['by']), 'reverse' => (bool)$sortpref['dir']));
+ $this->_sorted = $res['sort'];
+ } catch (Horde_Imap_Client_Exception $e) {
+ $GLOBALS['notification']->push(_("Mailbox listing failed") . ': ' . $e->getMessage(), 'horde.error');
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the list of new messages in the mailbox (IMAP RECENT flag, with
+ * UNDELETED if we're hiding deleted messages).
+ *
+ * @param integer $results A Horde_Imap_Client::SORT_* constant that
+ * indicates the desired return type.
+ * @param boolean $uid Return UIDs instead of sequence numbers (for
+ * $results queries that return message lists).
+ *
+ * @return mixed Whatever is requested in $results.
+ */
+ public function newMessages($results, $uid = false)
+ {
+ return $this->_msgFlagSearch('recent', $results, $uid);
+ }
+
+ /**
+ * Get the list of unseen messages in the mailbox (IMAP UNSEEN flag, with
+ * UNDELETED if we're hiding deleted messages).
+ *
+ * @param integer $results A Horde_Imap_Client::SORT_RESULTS_* constant
+ * that indicates the desired return type.
+ * @param boolean $uid Return UIDs instead of sequence numbers (for
+ * $results queries that return message lists).
+ *
+ * @return mixed Whatever is requested in $results.
+ */
+ public function unseenMessages($results, $uid = false)
+ {
+ return $this->_msgFlagSearch('unseen', $results, $uid);
+ }
+
+ /**
+ * Do a search on a mailbox in the most efficient way available.
+ *
+ * @param string $type The search type - either 'recent' or 'unseen'.
+ * @param integer $results A Horde_Imap_Client::SORT_RESULTS_* constant
+ * that indicates the desired return type.
+ * @param boolean $uid Return UIDs instead of sequence numbers (for
+ * $results queries that return message lists).
+ *
+ * @return mixed Whatever is requested in $results.
+ */
+ protected function _msgFlagSearch($type, $results, $uid)
+ {
+ $count = ($results == Horde_Imap_Client::SORT_RESULTS_COUNT);
+
+ if ($this->_searchmbox || empty($this->_sorted)) {
+ if ($count &&
+ $this->_searchmbox &&
+ ($type == 'unseen') &&
+ $GLOBALS['injector']->getInstance('IMP_Search')->isVinbox($this->_mailbox)) {
+ return count($this);
+ }
+
+ return $count ? 0 : array();
+ }
+
+ $criteria = new Horde_Imap_Client_Search_Query();
+ $imp_imap = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb();
+
+ if (IMP::hideDeletedMsgs($this->_mailbox)) {
+ $criteria->flag('\\deleted', false);
+ } elseif ($count) {
+ try {
+ $status_res = $imp_imap->status($this->_mailbox, $type == 'recent' ? Horde_Imap_Client::STATUS_RECENT : Horde_Imap_Client::STATUS_UNSEEN);
+ return $status_res[$type];
+ } catch (Horde_Imap_Client_Exception $e) {
+ return 0;
+ }
+ }
+
+ if ($type == 'recent') {
+ $criteria->flag('\\recent', true);
+ } else {
+ $criteria->flag('\\seen', false);
+ }
+
+ try {
+ $res = $imp_imap->search($this->_mailbox, $criteria, array('results' => array($results), 'sequence' => !$uid));
+ return $count ? $res['count'] : $res;
+ } catch (Horde_Imap_Client_Exception $e) {
+ return $count ? 0 : array();
+ }
+ }
+
+ /**
+ * Using the preferences and the current mailbox, determines the messages
+ * to view on the current page.
+ *
+ * @param integer $page The page number currently being displayed.
+ * @param integer $start The starting message number.
+ *
+ * @return array An array with the following fields:
+ * <pre>
+ * 'anymsg' - (boolean) Are there any messages at all in mailbox? E.g. If
+ * 'msgcount' is 0, there may still be hidden deleted messages.
+ * 'begin' - (integer) The beginning message sequence number of the page.
+ * 'end' - (integer) The ending message sequence number of the page.
+ * 'index' - (integer) The index of the starting message.
+ * 'msgcount' - (integer) The number of viewable messages in the current
+ * mailbox.
+ * 'page' - (integer) The current page number.
+ * 'pagecount' - (integer) The number of pages in this mailbox.
+ * </pre>
+ */
+ public function buildMailboxPage($page = 0, $start = 0, $opts = array())
+ {
+ $this->_buildMailbox();
+
+ $ret = array('msgcount' => count($this->_sorted));
+
+ $page_size = $GLOBALS['prefs']->getValue('max_msgs');
+
+ if ($ret['msgcount'] > $page_size) {
+ $ret['pagecount'] = ceil($ret['msgcount'] / $page_size);
+
+ /* Determine which page to display. */
+ if (empty($page) || strcspn($page, '0123456789')) {
+ if (!empty($start)) {
+ /* Messages set this when returning to a mailbox. */
+ $page = ceil($start / $page_size);
+ } else {
+ /* Search for the last visited page first. */
+ if (isset($_SESSION['imp']['cache']['mbox_page'][$this->_mailbox])) {
+ $page = $_SESSION['imp']['cache']['mbox_page'][$this->_mailbox];
+ } elseif ($this->_searchmbox) {
+ $page = 1;
+ } else {
+ $page = ceil($this->mailboxStart($ret['msgcount']) / $page_size);
+ }
+ }
+ }
+
+ /* Make sure we're not past the end or before the beginning, and
+ that we have an integer value. */
+ $ret['page'] = intval($page);
+ if ($ret['page'] > $ret['pagecount']) {
+ $ret['page'] = $ret['pagecount'];
+ } elseif ($ret['page'] < 1) {
+ $ret['page'] = 1;
+ }
+
+ $ret['begin'] = (($ret['page'] - 1) * $page_size) + 1;
+ $ret['end'] = $ret['begin'] + $page_size - 1;
+ if ($ret['end'] > $ret['msgcount']) {
+ $ret['end'] = $ret['msgcount'];
+ }
+ } else {
+ $ret['begin'] = 1;
+ $ret['end'] = $ret['msgcount'];
+ $ret['page'] = 1;
+ $ret['pagecount'] = 1;
+ }
+
+ $ret['index'] = $ret['begin'] - 1;
+
+ /* If there are no viewable messages, check for deleted messages in
+ the mailbox. */
+ $ret['anymsg'] = true;
+ if (!$ret['msgcount'] && !$this->_searchmbox) {
+ try {
+ $status = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->status($this->_mailbox, Horde_Imap_Client::STATUS_MESSAGES);
+ $ret['anymsg'] = (bool)$status['messages'];
+ } catch (Horde_Imap_Client_Exception $e) {
+ $ret['anymsg'] = false;
+ }
+ }
+
+ /* Store the page value now. */
+ $_SESSION['imp']['cache']['mbox_page'][$this->_mailbox] = $ret['page'];
+
+ return $ret;
+ }
+
+ /**
+ * Determines the sequence number of the first message to display, based
+ * on the user's preferences.
+ *
+ * @param integer $total The total number of messages in the mailbox.
+ *
+ * @return integer The sequence number in the sorted mailbox.
+ */
+ public function mailboxStart($total)
+ {
+ if ($this->_searchmbox) {
+ return 1;
+ }
+
+ switch ($GLOBALS['prefs']->getValue('mailbox_start')) {
+ case IMP::MAILBOX_START_FIRSTPAGE:
+ return 1;
+
+ case IMP::MAILBOX_START_LASTPAGE:
+ return $total;
+
+ case IMP::MAILBOX_START_FIRSTUNSEEN:
+ $sortpref = IMP::getSort($this->_mailbox);
+
+ /* Optimization: if sorting by sequence then first unseen
+ * information is returned via a SELECT/EXAMINE call. */
+ if ($sortpref['by'] == Horde_Imap_Client::SORT_SEQUENCE) {
+ try {
+ $res = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->status($this->_mailbox, Horde_Imap_Client::STATUS_FIRSTUNSEEN);
+ if (!is_null($res['firstunseen'])) {
+ return $res['firstunseen'];
+ }
+ } catch (Horde_Imap_Client_Exception $e) {}
+
+ return 1;
+ }
+
+ $unseen_msgs = $this->unseenMessages(Horde_Imap_Client::SORT_RESULTS_MIN, true);
+ return empty($unseen_msgs['min'])
+ ? 1
+ : ($this->getArrayIndex($unseen_msgs['min']) + 1);
+
+ case IMP::MAILBOX_START_LASTUNSEEN:
+ $unseen_msgs = $this->unseenMessages(Horde_Imap_Client::SORT_RESULTS_MAX, true);
+ return empty($unseen_msgs['max'])
+ ? 1
+ : ($this->getArrayIndex($unseen_msgs['max']) + 1);
+ }
+ }
+
+ /**
+ * Get the Horde_Imap_Client_Thread object for the current mailbox.
+ *
+ * @return Horde_Imap_Client_Thread The thread object for the current
+ * mailbox.
+ */
+ public function getThreadOb()
+ {
+ if (is_null($this->_threadob)) {
+ try {
+ $this->_threadob = $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->thread($this->_mailbox, array('criteria' => $_SESSION['imp']['imap']['thread']));
+ } catch (Horde_Imap_Client_Exception $e) {
+ $GLOBALS['notification']->push($e);
+ return new Horde_Imap_Client_Thread(array(), 'uid');
+ }
+ }
+
+ return $this->_threadob;
+ }
+
+ /**
+ * Determines if a rebuild is needed, and, if necessary, performs
+ * the rebuild.
+ *
+ * @param boolean $force Force a rebuild?
+ */
+ protected function _rebuild($force = false)
+ {
+ if ($force) {
+ $this->_sorted = null;
+ $this->_buildMailbox();
+ }
+ }
+
+ /**
+ * Returns the array index of the given message UID.
+ *
+ * @param integer $uid The message UID.
+ * @param integer $mbox The message mailbox (defaults to the current
+ * mailbox).
+ *
+ * @return mixed The array index of the location of the message UID in
+ * the current mailbox. Returns null if not found.
+ */
+ public function getArrayIndex($uid, $mbox = null)
+ {
+ $aindex = null;
+
+ $this->_buildMailbox();
+
+ if ($this->_searchmbox) {
+ if (is_null($mbox)) {
+ $mbox = IMP::$thismailbox;
+ }
+
+ /* Need to compare both mbox name and message UID to obtain the
+ * correct array index since there may be duplicate UIDs. */
+ foreach (array_keys($this->_sorted, $uid) as $key) {
+ if ($this->_sortedMbox[$key] == $mbox) {
+ return $key;
+ }
+ }
+ } else {
+ /* array_search() returns false on no result. We will set an
+ * unsuccessful result to NULL. */
+ if (($aindex = array_search($uid, $this->_sorted)) === false) {
+ $aindex = null;
+ }
+ }
+
+ return $aindex;
+ }
+
+ /**
+ * Returns a raw sorted list of the mailbox.
+ *
+ * @return array An array with two keys: 's' = sorted UIDS list, 'm' =
+ * sorted mailboxes list.
+ */
+ public function getSortedList()
+ {
+ $this->_buildMailbox();
+
+ /* For exterior use, the array needs to begin numbering at 1. */
+ $s = $this->_sorted;
+ array_unshift($s, 0);
+ unset($s[0]);
+ $m = $this->_sortedMbox;
+ array_unshift($m, 0);
+ unset($m[0]);
+
+ return array('s' => $s, 'm' => $m);
+ }
+
+ /**
+ * Returns the current sorted array without the given messages.
+ *
+ * @param mixed $indices An IMP_Indices object or true to remove all
+ * messages in the mailbox.
+ *
+ * @return boolean True if the message was removed from the mailbox.
+ */
+ public function removeMsgs($indices)
+ {
+ if ($indices === true) {
+ $this->_rebuild(true);
+ return false;
+ }
+
+ if (!count($indices)) {
+ return false;
+ }
+
+ /* Remove the current entry and recalculate the range. */
+ foreach ($indices as $mbox => $uid) {
+ $val = $this->getArrayIndex($uid, $mbox);
+ unset($this->_sorted[$val]);
+ if ($this->_searchmbox) {
+ unset($this->_sortedMbox[$val]);
+ }
+ }
+
+ $this->changed = true;
+ $this->_sorted = array_values($this->_sorted);
+ if ($this->_searchmbox) {
+ $this->_sortedMbox = array_values($this->_sortedMbox);
+ }
+ $this->_threadob = null;
+
+ return true;
+ }
+
+ /**
+ * Returns a unique identifier for the current mailbox status.
+ *
+ * This cache ID is guaranteed to change if messages are added/deleted from
+ * the mailbox. Additionally, if CONDSTORE is available on the remote
+ * IMAP server, this ID will change if flag information changes.
+ *
+ * @return string The cache ID string, which will change when the
+ * composition of the mailbox changes.
+ */
+ public function getCacheID()
+ {
+ if (!$this->_searchmbox) {
+ $sortpref = IMP::getSort($this->_mailbox, true);
+ try {
+ return $GLOBALS['injector']->getInstance('IMP_Imap')->getOb()->getCacheId($this->_mailbox, array($sortpref['by'], $sortpref['dir']));
+ } catch (Horde_Imap_Client_Exception $e) {}
+ }
+
+ return strval(new Horde_Support_Randomid());
+ }
+
+ /* Countable methods. */
+
+ /**
+ * Returns the current message count of the mailbox.
+ *
+ * @return integer The mailbox message count.
+ */
+ public function count()
+ {
+ $this->_buildMailbox();
+ return count($this->_sorted);
+ }
+
+ /* Serializable methods. */
+
+ /**
+ * Serialization.
+ *
+ * @return string Serialized data.
+ */
+ public function serialize()
+ {
+ $data = array(
+ 'm' => $this->_mailbox,
+ 's' => $this->_searchmbox,
+ 'v' => self::VERSION
+ );
+
+ if (!is_null($this->_sorted)) {
+ $data['so'] = $this->_sorted;
+ if (!empty($this->_sortedmbox)) {
+ $data['som'] = $this->_sortedmbox;
+ }
+ }
+
+ foreach ($this->_slist as $val) {
+ $data[$val] = $this->$val;
+ }
+
+ return json_encode($data);
+ }
+
+ /**
+ * Unserialization.
+ *
+ * @param string $data Serialized data.
+ *
+ * @throws Exception
+ */
+ public function unserialize($data)
+ {
+ $data = json_decode($data, true);
+ if (!is_array($data) ||
+ !isset($data['v']) ||
+ ($data['v'] != self::VERSION)) {
+ throw new Exception('Cache version change');
+ }
+
+ $this->_mailbox = $data['m'];
+ $this->_searchmbox = $data['s'];
+
+ if (isset($data['so'])) {
+ $this->_sorted = $data['so'];
+ if (isset($data['som'])) {
+ $this->_sortedmbox = $data['som'];
+ }
+ }
+
+ foreach ($this->_slist as $val) {
+ $this->$val = $data[$val];
+ }
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * This class contains code related to generating and handling a mailbox
+ * message list. This class will keep track of the current index within
+ * a mailbox.
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ *
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @category Horde
+ * @license http://www.fsf.org/copyleft/gpl.html GPL
+ * @package IMP
+ */
+class IMP_Mailbox_List_Track extends IMP_Mailbox_List
+{
+ /**
+ * The location in the sorted array we are at.
+ *
+ * @var integer
+ */
+ protected $_index = null;
+
+ /**
+ * The list of additional variables to serialize.
+ *
+ * @var array
+ */
+ protected $_slist = array('_index');
+
+ /**
+ * Returns the current message array index. If the array index has
+ * run off the end of the message array, will return the last index.
+ *
+ * @return integer The message array index.
+ */
+ public function getMessageIndex()
+ {
+ return $this->isValidIndex()
+ ? ($this->_index + 1)
+ : 1;
+ }
+
+ /**
+ * Checks to see if the current index is valid.
+ *
+ * @return boolean True if index is valid, false if not.
+ */
+ public function isValidIndex()
+ {
+ return !is_null($this->_index);
+ }
+
+ /**
+ * Returns IMAP mbox/UID information on a message.
+ *
+ * @param integer $offset The offset from the current message.
+ *
+ * @return array Array with the following entries:
+ * <pre>
+ * 'mailbox' - (string) The mailbox.
+ * 'uid' - (integer) The message UID.
+ * </pre>
+ */
+ public function getIMAPIndex($offset = 0)
+ {
+ $index = $this->_index + $offset;
+
+ return isset($this->_sorted[$index])
+ ? array(
+ 'mailbox' => ($this->_searchmbox ? $this->_sortedMbox[$index] : $this->_mailbox),
+ 'uid' => $this->_sorted[$index]
+ )
+ : array();
+ }
+
+ /**
+ * Using the preferences and the current mailbox, determines the messages
+ * to view on the current page.
+ *
+ * @see parent::buildMailboxPage()
+ */
+ public function buildMailboxPage($page = 0, $start = 0, $opts = array())
+ {
+ $ret = parent::buildMailboxPage($page, $start, $opts);
+
+ if (!$this->_searchmbox) {
+ $ret['index'] = $this->_index;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Updates the message array index.
+ *
+ * @param mixed $data If an integer, the number of messages to increase
+ * array index by. If an indices object, sets array
+ * index to the index value.
+ */
+ public function setIndex($data)
+ {
+ if ($data instanceof IMP_Indices) {
+ list($mailbox, $uid) = $data->getSingle();
+ $this->_index = $this->getArrayIndex($uid, $mailbox);
+ if (empty($this->_index)) {
+ $this->_rebuild(true);
+ $this->_index = $this->getArrayIndex($uid, $mailbox);
+ }
+ } elseif (!is_null($this->_index)) {
+ $index = $this->_index += $data;
+ if (isset($this->_sorted[$this->_index])) {
+ $this->_rebuild();
+ } else {
+ $this->_rebuild(true);
+ $this->_index = isset($this->_sorted[$index])
+ ? $index
+ : null;
+ }
+ }
+ }
+
+ /**
+ * Determines if a rebuild is needed, and, if necessary, performs
+ * the rebuild.
+ *
+ * @param boolean $force Force a rebuild?
+ */
+ protected function _rebuild($force = false)
+ {
+ if ($force ||
+ (!is_null($this->_index) && !$this->getIMAPIndex(1))) {
+ $this->_sorted = null;
+ $this->_buildMailbox();
+ }
+ }
+
+ /**
+ * Returns the current sorted array without the given messages.
+ *
+ * @param mixed $indices An IMP_Indices object or true to remove all
+ * messages in the mailbox.
+ */
+ public function removeMsgs($indices)
+ {
+ if (parent::removeMsgs($indices)) {
+ /* Update the current array index to its new position in the
+ * message array. */
+ $this->setIndex(0);
+ }
+ }
+
+}
* <pre>
* 'create' - (boolean) Should the target mailbox be created?
* DEFAULT: false
- * 'mailboxob' - (IMP_Mailbox) Update this mailbox object.
+ * 'mailboxob' - (IMP_Mailbox_List) Update this mailbox object.
* DEFAULT: No update.
* </pre>
*
* <pre>
* 'keeplog' - (boolean) Should any history information of the message be
* kept?
- * 'mailboxob' - (IMP_Mailbox) Update this mailbox object.
+ * 'mailboxob' - (IMP_Mailbox_List) Update this mailbox object.
* DEFAULT: No update.
* 'nuke' - (boolean) Override user preferences and nuke (i.e. permanently
* delete) the messages instead?
* parts are stripped if null.
* @param array $opts Additional options:
* <pre>
- * 'mailboxob' - (IMP_Mailbox) Update this mailbox object.
+ * 'mailboxob' - (IMP_Mailbox_List) Update this mailbox object.
* DEFAULT: No update.
* </pre>
*
* <pre>
* 'list' - (boolean) Return a list of messages expunged.
* DEFAULT: false
- * 'mailboxob' - (IMP_Mailbox) Update this mailbox object.
+ * 'mailboxob' - (IMP_Mailbox_List) Update this mailbox object.
* DEFAULT: No update.
* </pre>
*
* @param string $action Either 'spam' or 'notspam'.
* @param array $opts Additional options:
* <pre>
- * 'mailboxob' - (IMP_Mailbox) Update this mailbox object.
+ * 'mailboxob' - (IMP_Mailbox_List) Update this mailbox list object.
* DEFAULT: No update.
* 'noaction' - (boolean) Don't perform any action after reporting?
* DEFAULT: false
}
/* Generate the sorted mailbox list now. */
- $imp_mailbox = $GLOBALS['injector']->getInstance('IMP_Mailbox')->getOb($mbox);
+ $imp_mailbox = $GLOBALS['injector']->getInstance('IMP_Mailbox_List')->getList($mbox);
$sorted_list = $imp_mailbox->getSortedList();
$msgcount = count($sorted_list['s']);
/**
* Obtains IMAP overview data for a given set of message UIDs.
*
- * @param IMP_Mailbox $imp_mailbox An IMP_Mailbox:: object.
- * @param string $folder The current folder.
- * @param array $msglist The list of message sequence numbers
- * to process.
- * @param boolean $search Is this a search mbox?
+ * @param IMP_Mailbox_List $imp_mailbox The mailbox list object.
+ * @param string $folder The current folder.
+ * @param array $msglist The list of message sequence
+ * numbers to process.
+ * @param boolean $search Is this a search mbox?
*
* @return array TODO
* @throws Horde_Exception
}
/* Build the list of messages in the mailbox. */
-$imp_mailbox = $injector->getInstance('IMP_Mailbox')->getOb(IMP::$mailbox);
+$imp_mailbox = $injector->getInstance('IMP_Mailbox_List')->getList(IMP::$mailbox);
$pageOb = $imp_mailbox->buildMailboxPage($vars->p, $vars->s);
/* Generate page title. */
}
/* Build the list of messages in the mailbox. */
-$imp_mailbox = $injector->getInstance('IMP_Mailbox')->getOb(IMP::$mailbox);
+$imp_mailbox = $injector->getInstance('IMP_Mailbox_List')->getList(IMP::$mailbox);
$pageOb = $imp_mailbox->buildMailboxPage($vars->page, $start);
$show_preview = $prefs->getValue('preview_enabled');
$vars = Horde_Variables::getDefaultVariables();
/* Make sure we have a valid index. */
-$imp_mailbox = $injector->getInstance('IMP_Mailbox')->getOb(IMP::$mailbox, new IMP_Indices(IMP::$thismailbox, IMP::$uid));
+$imp_mailbox = $injector->getInstance('IMP_Mailbox_List')->getListTrack(IMP::$mailbox, new IMP_Indices(IMP::$thismailbox, IMP::$uid));
if (!$imp_mailbox->isValidIndex()) {
IMP::generateIMPUrl('mailbox-mimp.php', IMP::$mailbox)->add('a', 'm')->redirect();
}
}
/* Make sure we have a valid index. */
-$imp_mailbox = $injector->getInstance('IMP_Mailbox')->getOb(IMP::$mailbox, new IMP_Indices(IMP::$thismailbox, IMP::$uid));
+$imp_mailbox = $injector->getInstance('IMP_Mailbox_List')->getListTrack(IMP::$mailbox, new IMP_Indices(IMP::$thismailbox, IMP::$uid));
if (!$imp_mailbox->isValidIndex()) {
_returnToMailbox(null, 'message_missing');
require IMP_BASE . '/mailbox.php';
$new_mail = (isset($request_parts[1]) && ($request_parts[1] === 'new'));
}
-$imp_mailbox = $injector->getInstance('IMP_Mailbox')->getOb($mailbox);
+$imp_mailbox = $injector->getInstance('IMP_Mailbox_List')->getList($mailbox);
$imp_search = $injector->getInstance('IMP_Search');
/* Obtain some information describing the mailbox state. */
: 'thread';
$imp_imap = $injector->getInstance('IMP_Imap')->getOb();
-$imp_mailbox = $injector->getInstance('IMP_Mailbox')->getOb(IMP::$mailbox, new IMP_Indices(IMP::$thismailbox, IMP::$uid));
+$imp_mailbox = $injector->getInstance('IMP_Mailbox_List')->getListTrack(IMP::$mailbox, new IMP_Indices(IMP::$thismailbox, IMP::$uid));
$error = false;
if ($mode == 'thread') {