From 6417dd030a843eee8b2ceb03774bb03995f5d6bc Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Fri, 27 Mar 2009 15:09:17 -0600 Subject: [PATCH] Sanity checking. Don't do message operations reliant on UID list if UIDVALIDITY of mailbox has changed. --- imp/docs/CHANGES | 2 ++ imp/lib/Imap.php | 38 ++++++++++++++++++++++ imp/lib/Message.php | 94 +++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 114 insertions(+), 20 deletions(-) diff --git a/imp/docs/CHANGES b/imp/docs/CHANGES index 867f7ba0b..022fa8d58 100644 --- a/imp/docs/CHANGES +++ b/imp/docs/CHANGES @@ -2,6 +2,8 @@ v5.0-git -------- +[mms] Sanity check - don't do message operations reliant on UID list if + UIDVALIDITY of mailbox has changed. [mms] Simplify forwarding - always attach entire message. [mms] Remember splitbar position on login/refresh (DIMP). [mms] Disable some advanced functions if using POP3 driver (caching, diff --git a/imp/lib/Imap.php b/imp/lib/Imap.php index f5c1cae44..63bdd3776 100644 --- a/imp/lib/Imap.php +++ b/imp/lib/Imap.php @@ -49,6 +49,13 @@ class IMP_Imap protected $_nsdefault; /** + * UIDVALIDITY check cache. + * + * @var array + */ + protected $_uidvalid = array(); + + /** * Constructor. */ function __construct() @@ -262,6 +269,37 @@ class IMP_Imap } /** + * Do a UIDVALIDITY check - needed if UIDs are passed between page + * accesses. + * + * @param string $mailbox The mailbox to check. Must be an IMAP mailbox. + * + * @throws Horde_Exception + */ + public function checkUidvalidity($mailbox) + { + // TODO: POP3 also? + if ($_SESSION['imp']['protocol'] == 'pop') { + return; + } + + if (!isset($this->_uidvalid[$mailbox])) { + $status = $this->ob->status($mailbox, Horde_Imap_Client::STATUS_UIDVALIDITY); + $ptr = &$_SESSION['imp']['cache']; + $val = isset($ptr['uidvalid'][$mailbox]) + ? $ptr['uidvalid'][$mailbox] + : null; + $ptr['uidvalid'][$mailbox] = $status['uidvalidity']; + + $this->_uidvalid[$mailbox] = (!is_null($val) && ($status['uidvalidity'] != $val)); + } + + if ($this->_uidvalid[$mailbox]) { + throw new Horde_Exception(_("Mailbox structure on server has changed.")); + } + } + + /** * Logs an exception from Horde_Imap_Client. * * @param object Horde_Imap_Client_Exception $e The exception object. diff --git a/imp/lib/Message.php b/imp/lib/Message.php index 043528e72..dffc48d23 100644 --- a/imp/lib/Message.php +++ b/imp/lib/Message.php @@ -118,23 +118,38 @@ class IMP_Message } foreach ($msgList as $mbox => $msgIndices) { + $error = null; + if (($action == 'move') && $GLOBALS['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; + $error = _("The target directory is read-only."); + } + + if (!$error) { + try { + $GLOBALS['imp_imap']->checkUidvalidity($mbox); + } catch (Horde_Exception $e) { + $error = $e->getMessage(); + } } /* Attempt to copy/move messages to new mailbox. */ - try { - $GLOBALS['imp_imap']->ob->copy($mbox, $targetMbox, array('ids' => $msgIndices, 'move' => $imap_move)); + if (!$error) { + try { + $GLOBALS['imp_imap']->ob->copy($mbox, $targetMbox, array('ids' => $msgIndices, 'move' => $imap_move)); - $imp_mailbox = IMP_Mailbox::singleton($mbox); - if (($action == 'move') && $imp_mailbox->isBuilt()) { - $imp_mailbox->removeMsgs(array($mbox => $msgIndices)); + $imp_mailbox = IMP_Mailbox::singleton($mbox); + if (($action == 'move') && $imp_mailbox->isBuilt()) { + $imp_mailbox->removeMsgs(array($mbox => $msgIndices)); + } + } catch (Horde_Imap_Client_Exception $e) { + $error = $e->getMessage(); } - } catch (Horde_Imap_Client_Exception $e) { - $notification->push(sprintf($message, IMP::displayFolder($mbox), IMP::displayFolder($targetMbox)) . ': ' . $e->getMessage(), 'horde.error'); + } + + if ($error) { + $notification->push(sprintf($message, IMP::displayFolder($mbox), IMP::displayFolder($targetMbox)) . ': ' . $error, 'horde.error'); $return_value = false; + continue; } } @@ -187,8 +202,22 @@ class IMP_Message } foreach ($msgList as $mbox => $msgIndices) { + $error = null; + if ($GLOBALS['imp_imap']->isReadOnly($mbox)) { - $notification->push(sprintf(_("There was an error deleting messages from the folder \"%s\". This folder is read-only."), IMP::displayFolder($mbox)), 'horde.error'); + $error = _("This folder is read-only."); + } + + if (!$error) { + try { + $GLOBALS['imp_imap']->checkUidvalidity($mbox); + } catch (Horde_Exception $e) { + $error = $e->getMessage(); + } + } + + if ($error) { + $notification->push(sprintf(_("There was an error deleting messages from the folder \"%s\"."), IMP::displayFolder($mbox)) . ' ' . $error, 'horde.error'); $return_value = false; continue; } @@ -449,6 +478,8 @@ class IMP_Message throw new Horde_Exception(_("Cannot strip the MIME part as the mailbox is read-only")); } + $GLOBALS['imp_imap']->checkUidvalidity($mbox); + /* Get a local copy of the message. */ $contents = IMP_Contents::singleton($index . IMP::IDX_SEP . $mbox); @@ -530,8 +561,6 @@ class IMP_Message */ public function flag($flags, $indices, $action = true) { - global $notification; - if (!($msgList = IMP::parseIndicesList($indices))) { return false; } @@ -541,16 +570,31 @@ class IMP_Message : array('remove' => $flags); foreach ($msgList as $mbox => $msgIndices) { + $error = null; + if ($GLOBALS['imp_imap']->isReadOnly($mbox)) { - $notification->push(sprintf(_("There was an error flagging messages in the folder \"%s\". This folder is read-only."), IMP::displayFolder($mbox)), 'horde.error'); - continue; + $error = _("This folder is read-only."); } - /* Flag/unflag the messages now. */ - try { - $GLOBALS['imp_imap']->ob->store($mbox, array_merge($action_array, array('ids' => $msgIndices))); - } catch (Horde_Imap_Client_Exception $e) { - $notification->push(sprintf(_("There was an error flagging messages in the folder \"%s\". This is what the server said"), IMP::displayFolder($mbox)) . ': ' . $e->getMessage(), 'horde.error'); + if (!$error) { + try { + $GLOBALS['imp_imap']->checkUidvalidity($mbox); + } catch (Horde_Exception $e) { + $error = $e->getMessage(); + } + } + + if (!$error) { + /* Flag/unflag the messages now. */ + try { + $GLOBALS['imp_imap']->ob->store($mbox, array_merge($action_array, array('ids' => $msgIndices))); + } catch (Horde_Imap_Client_Exception $e) { + $error = $e->getMessage(); + } + } + + if ($error) { + $GLOBALS['notification']->push(sprintf(_("There was an error flagging messages in the folder \"%s\". This folder is read-only."), IMP::displayFolder($mbox)), 'horde.error'); return false; } } @@ -630,6 +674,16 @@ class IMP_Message } foreach ($process_list as $key => $val) { + /* If expunging a particular UID list, need to check + * UIDVALIDITY. */ + if (is_array($val)) { + try { + $GLOBALS['imp_imap']->checkUidvalidity($key); + } catch (Horde_Exception $e) { + continue; + } + } + try { $update_list[$key] = $GLOBALS['imp_imap']->ob->expunge($key, array('ids' => is_array($val) ? $val : array(), 'list' => $msg_list)); -- 2.11.0