From ac0fc383fd43e8955b0ab22f70463159b14c74b0 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Mon, 23 Dec 2013 05:33:41 -0500
Subject: [PATCH] Fix so message flags modified by another client are applied on the list on refresh (#1485186)

---
 CHANGELOG                               |    1 
 program/steps/mail/list.inc             |   11 ++++-
 program/steps/mail/search.inc           |    7 +++
 program/steps/mail/check_recent.inc     |   18 +++++++++
 program/lib/Roundcube/rcube_imap.php    |   35 +++++++++++++++++
 program/lib/Roundcube/rcube_storage.php |   12 ++++++
 program/js/app.js                       |   19 ++++++++-
 7 files changed, 99 insertions(+), 4 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index b1eca46..ff09b2f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 CHANGELOG Roundcube Webmail
 ===========================
 
+- Fix so message flags modified by another client are applied on the list on refresh (#1485186)
 - Fix broken text/* attachments when forwarding/editing a message (#1489426)
 - Improved minified files handling, added css minification (#1486988)
 - Fix handling of X-Forwarded-For header with multiple addresses (#1489481)
diff --git a/program/js/app.js b/program/js/app.js
index 138fcbb..a001a3b 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -6923,6 +6923,16 @@
 
       case 'refresh':
       case 'check-recent':
+        // update message flags
+        $.each(this.env.recent_flags || {}, function(uid, flags) {
+          ref.set_message(uid, 'deleted', flags.deleted);
+          ref.set_message(uid, 'replied', flags.answered);
+          ref.set_message(uid, 'unread', !flags.seen);
+          ref.set_message(uid, 'forwarded', flags.forwarded);
+          ref.set_message(uid, 'flagged', flags.flagged);
+        });
+        delete this.env.recent_flags;
+
       case 'getunread':
       case 'search':
         this.env.qsearch = null;
@@ -7246,13 +7256,18 @@
 
     if (this.gui_objects.mailboxlist)
       params._folderlist = 1;
-    if (this.gui_objects.messagelist)
-      params._list = 1;
     if (this.gui_objects.quotadisplay)
       params._quota = 1;
     if (this.env.search_request)
       params._search = this.env.search_request;
 
+    if (this.gui_objects.messagelist) {
+      params._list = 1;
+
+      // message uids for flag updates check
+      params._uids = $.map(this.message_list.rows, function(row, uid) { return uid; }).join(',');
+    }
+
     return params;
   };
 
diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php
index f1363ca..4c3bf6f 100644
--- a/program/lib/Roundcube/rcube_imap.php
+++ b/program/lib/Roundcube/rcube_imap.php
@@ -680,6 +680,41 @@
 
 
     /**
+     * Public method for listing message flags
+     *
+     * @param string $folder  Folder name
+     * @param array  $uids    Message UIDs
+     * @param int    $mod_seq Optional MODSEQ value (of last flag update)
+     *
+     * @return array Indexed array with message flags
+     */
+    public function list_flags($folder, $uids, $mod_seq = null)
+    {
+        if (!strlen($folder)) {
+            $folder = $this->folder;
+        }
+
+        if (!$this->check_connection()) {
+            return array();
+        }
+
+        // @TODO: when cache was synchronized in this request
+        // we might already have asked for flag updates, use it.
+
+        $flags  = $this->conn->fetch($folder, $uids, true, array('FLAGS'), $mod_seq);
+        $result = array();
+
+        if (!empty($flags)) {
+            foreach ($flags as $message) {
+                $result[$message->uid] = $message->flags;
+            }
+        }
+
+        return $result;
+    }
+
+
+    /**
      * Public method for listing headers
      *
      * @param   string   $folder     Folder name
diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php
index e697b2c..ca65af1 100644
--- a/program/lib/Roundcube/rcube_storage.php
+++ b/program/lib/Roundcube/rcube_storage.php
@@ -360,6 +360,18 @@
 
 
     /**
+     * Public method for listing message flags
+     *
+     * @param string $folder  Folder name
+     * @param array  $uids    Message UIDs
+     * @param int    $mod_seq Optional MODSEQ value
+     *
+     * @return array Indexed array with message flags
+     */
+    abstract function list_flags($folder, $uids, $mod_seq = null);
+
+
+    /**
      * Public method for listing headers.
      *
      * @param   string   $folder     Folder name
diff --git a/program/steps/mail/check_recent.inc b/program/steps/mail/check_recent.inc
index 3aa7b3e..60da68a 100644
--- a/program/steps/mail/check_recent.inc
+++ b/program/steps/mail/check_recent.inc
@@ -114,6 +114,24 @@
             $OUTPUT->command('update_selection');
         }
     }
+    // handle flag updates
+    else if ($is_current && ($uids = rcube_utils::get_input_value('_uids', rcube_utils::INPUT_GPC))) {
+        $data = $RCMAIL->storage->folder_data($mbox_name);
+
+        if (empty($_SESSION['list_mod_seq']) || $_SESSION['list_mod_seq'] != $data['HIGHESTMODSEQ']) {
+            $flags = $RCMAIL->storage->list_flags($mbox_name, explode(',', $uids), $_SESSION['list_mod_seq']);
+            foreach ($flags as $idx => $row) {
+                $flags[$idx] = array_change_key_case(array_map('intval', $row));
+            }
+
+            // remember last HIGHESTMODSEQ value (if supported)
+            if (!empty($data['HIGHESTMODSEQ'])) {
+                $_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ'];
+            }
+
+            $RCMAIL->output->set_env('recent_flags', $flags);
+        }
+    }
 }
 
 // trigger refresh hook
diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc
index fe7991c..91c53e8 100644
--- a/program/steps/mail/list.inc
+++ b/program/steps/mail/list.inc
@@ -23,8 +23,8 @@
   return;
 }
 
-$save_arr       = array();
-$dont_override  = (array) $RCMAIL->config->get('dont_override');
+$save_arr      = array();
+$dont_override = (array) $RCMAIL->config->get('dont_override');
 
 // is there a sort type for this request?
 if ($sort = rcube_utils::get_input_value('_sort', rcube_utils::INPUT_GET)) {
@@ -104,6 +104,13 @@
   if ($search_request) {
     $OUTPUT->show_message('searchsuccessful', 'confirmation', array('nr' => $count));
   }
+
+  // remember last HIGHESTMODSEQ value (if supported)
+  // we need it for flag updates in check-recent
+  $data = $RCMAIL->storage->folder_data($mbox_name);
+  if (!empty($data['HIGHESTMODSEQ'])) {
+    $_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ'];
+  }
 }
 else {
   // handle IMAP errors (e.g. #1486905)
diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc
index 03d6de3..210bedb 100644
--- a/program/steps/mail/search.inc
+++ b/program/steps/mail/search.inc
@@ -131,6 +131,13 @@
   rcmail_js_message_list($result_h);
   if ($search_str)
     $OUTPUT->show_message('searchsuccessful', 'confirmation', array('nr' => $RCMAIL->storage->count(NULL, 'ALL')));
+
+  // remember last HIGHESTMODSEQ value (if supported)
+  // we need it for flag updates in check-recent
+  $data = $RCMAIL->storage->folder_data($mbox_name);
+  if (!empty($data['HIGHESTMODSEQ'])) {
+    $_SESSION['list_mod_seq'] = $data['HIGHESTMODSEQ'];
+  }
 }
 // handle IMAP errors (e.g. #1486905)
 else  if ($err_code = $RCMAIL->storage->get_error_code()) {

--
Gitblit v1.9.1