Fix mailbox updating so it doesn't break on message actions.
authorMichael M Slusarz <slusarz@curecanti.org>
Tue, 25 Nov 2008 04:01:04 +0000 (21:01 -0700)
committerMichael M Slusarz <slusarz@curecanti.org>
Tue, 25 Nov 2008 04:01:04 +0000 (21:01 -0700)
Still need to think yet more about how (or if) we should reimplement
message list caching, but that can be done later.

imp/lib/Mailbox.php
imp/lib/Message.php
imp/message.php

index 0fc3fba..026ba88 100644 (file)
@@ -353,8 +353,8 @@ class IMP_Mailbox
      */
     public function getMessageIndex()
     {
-        return is_null($this->_arrayIndex)
-            ? (is_null($this->_lastArrayIndex) ? 1 : $this->_lastArrayIndex + 1)
+        return (is_null($this->_arrayIndex) && is_null($this->_lastArrayIndex))
+            ? 1
             : $this->_arrayIndex + 1;
     }
 
@@ -365,9 +365,7 @@ class IMP_Mailbox
      */
     public function getMessageCount()
     {
-        if (!$GLOBALS['imp_search']->isVFolder($this->_mailbox)) {
-            $this->_buildMailbox();
-        }
+        $this->_buildMailbox();
         return count($this->_sorted);
     }
 
@@ -379,7 +377,7 @@ class IMP_Mailbox
      */
     public function isValidIndex()
     {
-        $this->_sortIfNeeded();
+        $this->_rebuild();
         return !is_null($this->_arrayIndex);
     }
 
@@ -488,7 +486,6 @@ class IMP_Mailbox
                     }
                 }
 
-                print_r($page_uid);
                 if (empty($page)) {
                     $page = is_null($page_uid)
                         ? 1
@@ -556,7 +553,7 @@ class IMP_Mailbox
                 if (empty($this->_sorted[$this->_arrayIndex])) {
                     $this->_arrayIndex = null;
                 }
-                $this->_sortIfNeeded();
+                $this->_rebuild();
             }
             break;
 
@@ -586,78 +583,23 @@ class IMP_Mailbox
     }
 
     /**
-     * Determines if a resort is needed, and, if necessary, performs
-     * the resort.
+     * Determines if a rebuild is needed, and, if necessary, performs
+     * the rebuild.
+     *
+     * @param boolean $force  Force a rebuild?
      */
-    protected function _sortIfNeeded()
+    protected function _rebuild($force = false)
     {
-        if (!is_null($this->_arrayIndex) &&
-            !$this->_searchmbox &&
-            !$this->getIMAPIndex(1)) {
+        if ($force ||
+            (!is_null($this->_arrayIndex) &&
+             !$this->_searchmbox &&
+             !$this->getIMAPIndex(1))) {
             $this->_build = false;
             $this->_buildMailbox();
         }
     }
 
     /**
-     * Returns the current sorted array without the given messages.
-     *
-     * @param array $msgs  The indices to remove.
-     *
-     * @return boolean  True if sorted array was updated without a call to
-     *                  _buildMailbox().
-     */
-    protected function _removeMsgs($msgs)
-    {
-        if (empty($msgs)) {
-            return;
-        }
-
-        if (!($msgList = IMP::parseIndicesList($msgs))) {
-            $msgList = array($this->_mailbox => $msgs);
-        }
-
-        $msgcount = 0;
-        $sortcount = count($this->_sorted);
-
-        /* Remove the current entry and recalculate the range. */
-        foreach ($msgList as $key => $val) {
-            // @todo $arrival is false here
-            foreach ($val as $index) {
-                $val = $this->getArrayIndex($index, $key);
-                if ($arrival !== false && isset($this->_sorted[$val])) {
-                    unset($arrival[$this->_sorted[$val]]);
-                }
-                unset($this->_sorted[$val]);
-                if ($this->_searchmbox) {
-                    unset($this->_sortedInfo[$val]);
-                }
-                ++$msgcount;
-            }
-        }
-
-        $this->_sorted = array_values($this->_sorted);
-        if ($this->_searchmbox) {
-            $this->_sortedInfo = array_values($this->_sortedInfo);
-        }
-
-        /* Update the current array index to its new position in the message
-         * array. */
-        $this->setIndex(0, 'offset');
-
-        /* If we have a sortlimit, it is possible the sort prefs will have
-         * changed after messages are expunged. */
-        if (!empty($GLOBALS['conf']['server']['sort_limit']) &&
-            ($sortcount > $GLOBALS['conf']['server']['sort_limit']) &&
-            (($sortcount - $msgcount) <= $GLOBALS['conf']['server']['sort_limit'])) {
-            $this->updateMailbox(self::UPDATE);
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
      * Returns the array index of the given message UID.
      *
      * @param integer $uid   The message UID.
@@ -718,19 +660,54 @@ class IMP_Mailbox
     }
 
     /**
-     * Returns a unique identifier for the current mailbox status.
+     * Returns the current sorted array without the given messages.
      *
-     * @return string  The cache ID string, which will change when the status
-     *                 of the mailbox changes.
+     * @param mixed $msgs  The list of indices to remove (see
+     *                     IMP::parseIndicesList()) or true to remove all
+     *                     messages in the mailbox.
      */
-    public function getCacheID()
+    public function removeMsgs($msgs)
     {
-        try {
-            $sortpref = IMP::getSort($this->_mailbox);
-            $ret = $GLOBALS['imp_imap']->ob->status($this->_mailbox, Horde_Imap_Client::STATUS_MESSAGES | Horde_Imap_Client::STATUS_UIDNEXT | Horde_Imap_Client::STATUS_UIDVALIDITY);
-            return implode('|', array($ret['messages'], $ret['uidnext'], $ret['uidvalidity'], $sortpref['by'], $sortpref['dir']));
-        } catch (Horde_Imap_Client_Exception $e) {
-            return '';
+        if ($msgs === true) {
+            $this->_rebuild(true);
+            return;
+        }
+
+        if (empty($msgs)) {
+            return;
+        }
+
+        $msgcount = 0;
+        $sortcount = count($this->_sorted);
+
+        /* Remove the current entry and recalculate the range. */
+        foreach (IMP::parseIndicesList($msgs) as $key => $val) {
+            foreach ($val as $index) {
+                $val = $this->getArrayIndex($index, $key);
+                unset($this->_sorted[$val]);
+                if ($this->_searchmbox) {
+                    unset($this->_sortedInfo[$val]);
+                }
+                ++$msgcount;
+            }
+        }
+
+        $this->_sorted = array_values($this->_sorted);
+        if ($this->_searchmbox) {
+            $this->_sortedInfo = array_values($this->_sortedInfo);
+        }
+
+        /* Update the current array index to its new position in the message
+         * array. */
+        $this->setIndex(0, 'offset');
+
+        /* If we have a sortlimit, it is possible the sort prefs will have
+         * changed after messages are expunged. */
+        if (!empty($GLOBALS['conf']['server']['sort_limit']) &&
+            ($sortcount > $GLOBALS['conf']['server']['sort_limit']) &&
+            (($sortcount - $msgcount) <= $GLOBALS['conf']['server']['sort_limit'])) {
+            $this->_rebuild(true);
         }
     }
+
 }
index 914839e..1875ed8 100644 (file)
@@ -5,11 +5,6 @@
  * handled in here so that code need not be repeated between mailbox, message,
  * and other pages.
  *
- * Indices format:
- * ===============
- * For any function below that requires an $indices parameter, see
- * IMP::parseIndicesList() for the list of allowable inputs.
- *
  * Copyright 2000-2001 Chris Hyde <chris@jeks.net>
  * Copyright 2000-2008 The Horde Project (http://www.horde.org/)
  *
@@ -35,6 +30,13 @@ class IMP_Message
     protected $_usepop = false;
 
     /**
+     * An IMP_Mailbox object to update on message actions.
+     *
+     * @var IMP_Mailbox
+     */
+    protected $_mailboxOb = null;
+
+    /**
      * Returns a reference to the global IMP_Message object, only creating it
      * if it doesn't already exist. This ensures that only one IMP_Message
      * instance is instantiated for any given session.
@@ -67,14 +69,24 @@ class IMP_Message
     }
 
     /**
-     * Copies or moves a list of messages to a new folder.
-     * Handles use of the IMP::SEARCH_MBOX mailbox and the Trash folder.
+     * Set the IMP_Mailbox object to update on message actions.
+     *
+     * @param IMP_Mailbox &$ob  An IMP_Mailbox object.
+     */
+    public function updateMailboxOb(&$ob)
+    {
+        $this->_mailboxOb = $ob;
+    }
+
+    /**
+     * Copies or moves a list of messages to a new mailbox.
+     * Handles use of the IMP::SEARCH_MBOX mailbox and the Trash mailbox.
      *
      * @param string $targetMbox  The mailbox to move/copy messages to
      *                            (UTF7-IMAP).
      * @param integer $action     Either IMP_Message::MOVE or
      *                            IMP_Message::COPY.
-     * @param mixed $indices      See above.
+     * @param mixed $indices      See IMP::parseIndicesList().
      * @param boolean $new        Whether the target mailbox has to be created.
      *
      * @return boolean  True if successful, false if not.
@@ -126,18 +138,21 @@ class IMP_Message
             break;
         }
 
-        foreach ($msgList as $folder => $msgIndices) {
-            if (($action == self::MOVE) && $imp_imap->isReadOnly($folder)) {
-                $notification->push(sprintf($message, IMP::displayFolder($folder), IMP::displayFolder($targetMbox)) . ': ' . _("The target directory is read-only."), 'horde.error');
+        foreach ($msgList as $mbox => $msgIndices) {
+            if (($action == self::MOVE) && $imp_imap->isReadOnly($mbox)) {
+                $notification->push(sprintf($message, IMP::displayFolder($mbox), IMP::displayFolder($targetMbox)) . ': ' . _("The target directory is read-only."), 'horde.error');
                 $return_value = false;
                 continue;
             }
 
             /* Attempt to copy/move messages to new mailbox. */
             try {
-                $imp_imap->ob->copy($folder, $targetMbox, array('ids' => $msgIndices, 'move' => $imap_move));
+                $imp_imap->ob->copy($mbox, $targetMbox, array('ids' => $msgIndices, 'move' => $imap_move));
+                if (!is_null($this->_mailboxOb)) {
+                    $this->_mailboxOb->removeMsgs(array($mbox => $msgIndices));
+                }
             } catch (Horde_Imap_Client_Exception $e) {
-                //$notification->push(sprintf($message, IMP::displayFolder($folder), IMP::displayFolder($targetMbox)) . ': ' . imap_last_error(), 'horde.error');
+                $notification->push(sprintf($message, IMP::displayFolder($mbox), IMP::displayFolder($targetMbox)) . ': ' . imap_last_error(), 'horde.error');
                 $return_value = false;
             }
         }
@@ -150,7 +165,7 @@ class IMP_Message
      * Trash folder is being used.
      * Handles use of the IMP::SEARCH_MBOX mailbox and the Trash folder.
      *
-     * @param mixed $indices    See above.
+     * @param mixed $indices    See IMP::parseIndicesList().
      * @param boolean $nuke     Override user preferences and nuke (i.e.
      *                          permanently delete) the messages instead?
      * @param boolean $keeplog  Should any history information of the
@@ -204,6 +219,9 @@ class IMP_Message
             if ($use_trash_folder && ($mbox != $trash)) {
                 try {
                     $imp_imap->ob->copy($mbox, $trash, array('ids' => $msgIndices, 'move' => true));
+                    if (!is_null($this->_mailboxOb)) {
+                        $this->_mailboxOb->removeMsgs(array($mbox => $msgIndices));
+                    }
                 } catch (Horde_Imap_Client_Exception $e) {
                     // @todo Check for overquota error.
                     return false;
@@ -268,7 +286,7 @@ class IMP_Message
      * Handles the IMP::SEARCH_MBOX mailbox.
      * This function works with IMAP only, not POP3.
      *
-     * @param mixed $indices  See above.
+     * @param mixed $indices  See IMP::parseIndicesList().
      *
      * @return boolean  True if successful, false if not.
      */
@@ -284,7 +302,7 @@ class IMP_Message
      * @param string $list      The list in which the task or note will be
      *                          created.
      * @param integer $action   Either IMP_Message::MOVE or IMP_Message::COPY.
-     * @param mixed $indices    See above.
+     * @param mixed $indices    See IMP::parseIndicesList().
      * @param string $type      The object type to create, defaults to task.
      *
      * @return boolean  True if successful, false if not.
@@ -518,7 +536,7 @@ class IMP_Message
      * This function works with IMAP only, not POP3.
      *
      * @param array $flags     The IMAP flag(s) to set or clear.
-     * @param mixed $indices   See above.
+     * @param mixed $indices   See IMP::parseIndicesList().
      * @param boolean $action  If true, set the flag(s), otherwise clear the
      *                         flag(s).
      *
@@ -629,6 +647,9 @@ class IMP_Message
         foreach ($process_list as $key => $val) {
             try {
                 $imp_imap->ob->expunge($key, array('ids' => is_array($val) ? $val : array()));
+                if (!is_null($this->_mailboxOb)) {
+                    $this->_mailboxOb->removeMsgs(is_array($val) ? array($key => $val) : true);
+                }
                 $update_list[$key] = $val;
             } catch (Horde_Imap_Client_Exception $e) {}
         }
index cd516ea..2a23f83 100644 (file)
@@ -44,6 +44,10 @@ if (!$imp_mailbox->isValidIndex()) {
     exit;
 }
 
+/* Update IMP_Mailbox on message actions. */
+$imp_message = &IMP_Message::singleton();
+$imp_message->updateMailboxOb($imp_mailbox);
+
 /* Set the current time zone. */
 NLS::setTimeZone();