From e538b3dc7d740c5a9213ef352437f249be856d3a Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Thu, 13 Nov 2008 05:30:06 -0500
Subject: [PATCH] - Added message status filter + fixes for r2046 (searching with SORT)

---
 skins/default/common.css          |    2 
 CHANGELOG                         |    1 
 program/steps/mail/list.inc       |   13 ++
 skins/default/templates/mail.html |    1 
 program/steps/mail/search.inc     |   33 ++++-
 program/include/rcube_imap.php    |  102 +++++++++++--------
 skins/default/mail.css            |   10 +
 program/steps/mail/func.inc       |   31 ++++++
 program/steps/mail/show.inc       |   17 +-
 program/js/app.js                 |   32 +++++
 10 files changed, 173 insertions(+), 69 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 9a06f85..d9bb23a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,6 +4,7 @@
 2008/11/12 (alec)
 ----------
 - Use SORT for searching on servers with SORT capability
+- Added message status filter
 
 2008/11/06 (alec)
 ----------
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 2ccaf77..765778a 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -61,7 +61,6 @@
   var $msg_headers = array();
   var $skip_deleted = FALSE;
   var $search_set = NULL;
-  var $search_subject = '';
   var $search_string = '';
   var $search_charset = '';
   var $search_sort_field = '';  
@@ -282,18 +281,18 @@
   /**
    * Save a set of message ids for future message listing methods
    *
-   * @param  array  List of IMAP fields to search in
-   * @param  string Search string
-   * @param  array  List of message ids or NULL if empty
+   * @param  string  IMAP Search query
+   * @param  array   List of message ids or NULL if empty
+   * @param  string  Charset of search string
+   * @param  string  Sorting field
    */
-  function set_search_set($subject, $str=null, $msgs=null, $charset=null, $sort_field=null)
+  function set_search_set($str=null, $msgs=null, $charset=null, $sort_field=null)
     {
-    if (is_array($subject) && $str == null && $msgs == null)
-      list($subject, $str, $msgs, $charset, $sort_field) = $subject;
+    if ($msgs == null)
+      list($str, $msgs, $charset, $sort_field) = $str;
     if ($msgs != null && !is_array($msgs))
       $msgs = split(',', $msgs);
       
-    $this->search_subject = $subject;
     $this->search_string = $str;
     $this->search_set = (array)$msgs;
     $this->search_charset = $charset;
@@ -307,7 +306,7 @@
    */
   function get_search_set()
     {
-    return array($this->search_subject, $this->search_string, $this->search_set, $this->search_charset, $this->search_sort_field);
+    return array($this->search_string, $this->search_set, $this->search_charset, $this->search_sort_field);
     }
 
 
@@ -654,9 +653,9 @@
     if ($this->get_capability('sort')) // SORT searching result
       {
       // reset search set if sorting field has been changed
-      if ($sort_field && $this->search_sort_field != $sort_field)
+      if ($this->sort_field && $this->search_sort_field != $this->sort_field)
         {
-        $msgs = $this->search('', $this->search_subject, $this->search_string, $this->search_charset, $sort_field);
+        $msgs = $this->search('', $this->search_string, $this->search_charset, $this->sort_field);
         }
 
       // return empty array if no messages found
@@ -783,7 +782,7 @@
     
   
   /**
-   * Return sorted array of message UIDs
+   * Return sorted array of message IDs (not UIDs)
    *
    * @param string Mailbox to get index from
    * @param string Sort column
@@ -801,10 +800,25 @@
     if (!isset($this->cache[$key]) && $this->search_string && $mailbox == $this->mailbox)
     {
       $this->cache[$key] = $a_msg_headers = array();
-      $this->_fetch_headers($mailbox, join(',', $this->search_set), $a_msg_headers, NULL);
+      
+      if ($this->get_capability('sort'))
+        {
+        if ($this->sort_field && $this->search_sort_field != $this->sort_field)
+          $this->search('', $this->search_string, $this->search_charset, $this->sort_field);
 
-      foreach (iil_SortHeaders($a_msg_headers, $this->sort_field, $this->sort_order) as $i => $msg)
-        $this->cache[$key][] = $msg->uid;
+	if ($this->sort_order == 'DESC')
+          $this->cache[$key] = array_reverse($this->search_set);
+	else
+	  $this->cache[$key] = $this->search_set;
+        }
+      else
+        {
+	// TODO: see list_header_set (fetch only one header field needed for sorting)
+        $this->_fetch_headers($mailbox, join(',', $this->search_set), $a_msg_headers, NULL);
+
+        foreach (iil_SortHeaders($a_msg_headers, $this->sort_field, $this->sort_order) as $i => $msg)
+          $this->cache[$key][] = $msg->id;
+	}
     }
 
     // have stored it in RAM
@@ -825,28 +839,23 @@
 
     // fetch complete message index
     $msg_count = $this->_messagecount($mailbox);
-    if ($this->get_capability('sort') && ($a_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, '', TRUE)))
+    if ($this->get_capability('sort') && ($a_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, '')))
       {
       if ($this->sort_order == 'DESC')
         $a_index = array_reverse($a_index);
 
       $this->cache[$key] = $a_index;
-
       }
     else
       {
       $a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, "1:$msg_count", $this->sort_field);
-      $a_uids = iil_C_FetchUIDs($this->conn, $mailbox);
-    
+
       if ($this->sort_order=="ASC")
         asort($a_index);
       else if ($this->sort_order=="DESC")
         arsort($a_index);
         
-      $i = 0;
-      $this->cache[$key] = array();
-      foreach ($a_index as $index => $value)
-        $this->cache[$key][$i++] = $a_uids[$index];
+      $this->cache[$key] = $a_index;
       }
 
     return $this->cache[$key];
@@ -906,39 +915,46 @@
    * Invoke search request to IMAP server
    *
    * @param  string  mailbox name to search in
-   * @param  string  search criteria (ALL, TO, FROM, SUBJECT, etc)
    * @param  string  search string
    * @param  string  search string charset
    * @param  string  header field to sort by
    * @return array   search results as list of message ids
    * @access public
    */
-  function search($mbox_name='', $criteria='ALL', $str=NULL, $charset=NULL, $sort_field=NULL)
+  function search($mbox_name='', $str=NULL, $charset=NULL, $sort_field=NULL)
     {
     $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
-    $search = '';
 
-    // have an array of criterias => create search string
-    if (is_array($criteria) && count($criteria) > 1)
-      $search .= 'OR';
-
-    $criteria = (array) $criteria;
-    foreach($criteria as $idx => $crit)
-      if ($str)
-        $search .= sprintf(" (%s {%d}\r\n%s)", $crit, strlen($str), $str);
-      else
-        $search .= '('. $crit .')';
-
-    $results = $this->_search_index($mailbox, $search, $charset, $sort_field);
+    $results = $this->_search_index($mailbox, $str, $charset, $sort_field);
 
     // try search with ISO charset (should be supported by server)
     if (empty($results) && !empty($charset) && $charset!='ISO-8859-1')
-      $results = $this->search($mbox_name, $criteria, rcube_charset_convert($str, $charset, 'ISO-8859-1'), 'ISO-8859-1', $sort_field);
+      {
+	// convert strings to ISO-8859-1
+        if(preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE))
+	  {
+	  $last = 0; $res = '';
+	  foreach($matches[1] as $m)
+	    {
+	    $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
+	    $string = substr($str, $string_offset - 1, $m[0]);
+	    $string = rcube_charset_convert($string, $charset, 'ISO-8859-1');
+	    $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string);
+	    $last = $m[0] + $string_offset - 1;
+	    }
+	    if ($last < strlen($str))
+	      $res .= substr($str, $last, strlen($str)-$last);
+	  }
+	else // strings for conversion not found
+	  $res = $str;
+	  
+	$results = $this->search($mbox_name, $res, 'ISO-8859-1', $sort_field);
+      }
 
-    $this->set_search_set($criteria, $str, $results, $charset, $sort_field);
+    $this->set_search_set($str, $results, $charset, $sort_field);
 
     return $results;
-    }    
+    }
 
 
   /**
@@ -974,8 +990,8 @@
    */
   function refresh_search()
     {
-    if (!empty($this->search_subject) && !empty($this->search_string))
-      $this->search_set = $this->search('', $this->search_subject, $this->search_string, $this->search_charset, $this->search_sort_field);
+    if (!empty($this->search_string))
+      $this->search_set = $this->search('', $this->search_string, $this->search_charset, $this->search_sort_field);
       
     return $this->get_search_set();
     }
diff --git a/program/js/app.js b/program/js/app.js
index d22b1fb..e7204d0 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -266,7 +266,7 @@
 
         this.set_page_buttons();
         
-        if (this.env.address_sources && !this.env.address_sources[this.env.source].readonly)
+        if (this.env.address_sources && this.env.address_sources[this.env.source] && !this.env.address_sources[this.env.source].readonly)
           this.enable_command('add', true);
         
         if (this.env.cid)
@@ -1414,6 +1414,24 @@
       }
     };
 
+  // list messages of a specific mailbox using filter
+  this.filter_mailbox = function(filter)
+    {
+      var search;
+      if (this.gui_objects.qsearchbox)
+        search = this.gui_objects.qsearchbox.value;
+      
+      this.message_list.clear();
+
+      // reset vars
+      this.env.current_page = 1;
+      this.set_busy(true, 'searching');
+      this.http_request('search', '_filter='+filter
+    	    + (search ? '&_q='+urlencode(search) : '')
+    	    + (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : ''), true);
+    }
+
+
   // list messages of a specific mailbox
   this.list_mailbox = function(mbox, page, sort)
     {
@@ -2283,7 +2301,7 @@
     };
 
   // send remote request to search mail or contacts
-  this.qsearch = function(value)
+  this.qsearch = function(value, addurl)
     {
     if (value != '')
       {
@@ -2292,12 +2310,18 @@
       else if (this.contact_list) {
         this.contact_list.clear(true);
         this.show_contentframe(false);
-      }
+        }
+
+      if (this.gui_objects.search_filter)
+	addurl = '&_filter=' + this.gui_objects.search_filter.value;
 
       // reset vars
       this.env.current_page = 1;
       this.set_busy(true, 'searching');
-      this.http_request('search', '_q='+urlencode(value)+(this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : '')+(this.env.source ? '&_source='+urlencode(this.env.source) : ''), true);
+      this.http_request('search', '_q='+urlencode(value)
+    	    +(this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : '')
+	    +(this.env.source ? '&_source='+urlencode(this.env.source) : '')
+	    +(addurl ? addurl : ''), true);
       }
     return true;
     };
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index ca7c4e7..d2bc6a9 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -1292,6 +1292,36 @@
 }
 
 
+function rcmail_search_filter($attrib)
+{
+  global $OUTPUT;
+
+  if (!strlen($attrib['id']))
+    $attrib['id'] = 'rcmlistfilter';
+
+  $attrib['onchange'] = JS_OBJECT_NAME.'.filter_mailbox(this.value)';
+  
+  /*
+    RFC3501 (6.4.4): 'ALL', 'RECENT', 
+    'ANSWERED', 'DELETED', 'FLAGGED', 'SEEN',
+    'UNANSWERED', 'UNDELETED', 'UNFLAGGED', 'UNSEEN',
+    'NEW', // = (RECENT UNSEEN)
+    'OLD' // = NOT RECENT
+  */
+
+  $select_filter = new html_select($attrib);
+  $select_filter->add(rcube_label('all'), 'ALL');
+  $select_filter->add(rcube_label('unread'), 'UNSEEN');
+  $select_filter->add(rcube_label('flagged'), 'FLAGGED');
+  $select_filter->add(rcube_label('unanswered'), 'UNANSWERED');
+
+  $out = $select_filter->show($_SESSION['search_filter']);
+
+  $OUTPUT->add_gui_object('search_filter', $attrib['id']);
+
+  return $out;										
+}
+
 // register UI objects
 $OUTPUT->add_handlers(array(
   'mailboxlist' => 'rcmail_mailbox_list',
@@ -1304,6 +1334,7 @@
   'messagecontentframe' => 'rcmail_messagecontent_frame',
   'messagepartframe' => 'rcmail_message_part_frame',
   'messagepartcontrols' => 'rcmail_message_part_controls',
+  'searchfilter' => 'rcmail_search_filter',
   'searchform' => array($OUTPUT, 'search_form'),
 ));
 
diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc
index a868f9c..2078262 100644
--- a/program/steps/mail/list.inc
+++ b/program/steps/mail/list.inc
@@ -41,6 +41,17 @@
 
 $mbox_name = $IMAP->get_mailbox_name();
 
+// initialize searching result if search_filter is used
+if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL')
+{
+  $search_request = md5($mbox_name.$_SESSION['search_filter']);
+
+  $IMAP->search($mbox_name, $_SESSION['search_filter'], RCMAIL_CHARSET, $sort_col);
+  $_SESSION['search'][$search_request] = $IMAP->get_search_set();
+  $OUTPUT->set_env('search_request', $search_request);
+}
+			      
+
 // fetch message headers
 if ($IMAP->messagecount($mbox_name, 'ALL', !empty($_REQUEST['_refresh'])))
   $a_headers = $IMAP->list_headers($mbox_name, NULL, $sort_col, $sort_order);
@@ -54,8 +65,6 @@
 $OUTPUT->set_env('pagecount', $pages);
 $OUTPUT->command('set_rowcount', rcmail_get_messagecount_text($count));
 $OUTPUT->command('set_mailboxname', rcmail_get_mailbox_name_text());
-
-
 
 // add message rows
 if (isset($a_headers) && count($a_headers))
diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc
index 6f36768..18335ba 100644
--- a/program/steps/mail/search.inc
+++ b/program/steps/mail/search.inc
@@ -26,51 +26,66 @@
 
 // get search string
 $str = get_input_value('_q', RCUBE_INPUT_GET);
+$filter = get_input_value('_filter', RCUBE_INPUT_GET);
 $mbox = get_input_value('_mbox', RCUBE_INPUT_GET);
-$search_request = md5($mbox.$str);
+$search_request = md5($mbox.$filter.$str);
 
+// add list filter string
+$search_str = $filter && $filter != 'ALL' ? $filter : '';
+
+$_SESSION['search_filter'] = $filter;
 
 // Check the search string for type of search
-if (preg_match("/^from:/i", $str))
+if (preg_match("/^from:.*/i", $str))
 {
   list(,$srch) = explode(":", $str);
-  $subject =  "HEADER FROM";
+  $subject = "HEADER FROM";
   $search = trim($srch);
 }
-else if (preg_match("/^to:/i", $str))
+else if (preg_match("/^to.*:/i", $str))
 {
   list(,$srch) = explode(":", $str);
   $subject = "HEADER TO";
   $search = trim($srch);
 }
-else if (preg_match("/^cc:/i", $str))
+else if (preg_match("/^cc:.*/i", $str))
 {
   list(,$srch) = explode(":", $str);
   $subject = "HEADER CC";
   $search = trim($srch);
 }
-else if (preg_match("/^subject:/i", $str))
+else if (preg_match("/^subject:.*/i", $str))
 {
   list(,$srch) = explode(":", $str);
   $subject = "HEADER SUBJECT";
   $search = trim($srch);
 }
-else if (preg_match("/^body:/i", $str))
+else if (preg_match("/^body:.*/i", $str))
 {
   list(,$srch) = explode(":", $str);
   $subject = "TEXT";
   $search = trim($srch);
 }
 // search in subject and sender by default
-else
+else if(trim($str))
 {
   $from = ($mbox == $CONFIG['sent_mbox'] || $mbox == $CONFIG['drafts_mbox']) ? "TO" : "FROM";
   $subject = array("HEADER SUBJECT", "HEADER $from");
   $search = trim($str);
 }
 
+if ($subject && !is_array($subject))
+  $search_str .= sprintf(" %s {%d}\r\n%s", $subject, strlen($search), $search);
+else if ($subject) {
+  $search_str .= ' OR';
+  foreach($subject as $sub)
+    $search_str .= sprintf(" (%s {%d}\r\n%s)", $sub, strlen($search), $search);
+}
+
+$search_str = trim($search_str);
+
 // execute IMAP search
-$result = $IMAP->search($mbox, $subject, $search, $imap_charset, $_SESSION['sort_col']);
+$result = $IMAP->search($mbox, $search_str, $imap_charset, $_SESSION['sort_col']);
 $count = 0;
 
 // Make sure our $result is legit..
diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc
index 8b36c9a..15c1c54 100644
--- a/program/steps/mail/show.inc
+++ b/program/steps/mail/show.inc
@@ -110,12 +110,13 @@
     {
     // Only if we use custom sorting
     $a_msg_index = $IMAP->message_index(NULL, $_SESSION['sort_col'], $_SESSION['sort_order']);
- 
-    $MESSAGE->index = array_search((string)$MESSAGE->uid, $a_msg_index, TRUE);
-    $prev = isset($a_msg_index[$MESSAGE->index-1]) ? $a_msg_index[$MESSAGE->index-1] : -1 ;
-    $first = count($a_msg_index)>0 ? $a_msg_index[0] : -1;
-    $next = isset($a_msg_index[$MESSAGE->index+1]) ? $a_msg_index[$MESSAGE->index+1] : -1 ;
-    $last = count($a_msg_index)>0 ? $a_msg_index[count($a_msg_index)-1] : -1;
+
+    $MESSAGE->index = array_search($IMAP->get_id($MESSAGE->uid), $a_msg_index);
+
+    $prev = isset($a_msg_index[$MESSAGE->index-1]) ? $IMAP->get_uid($a_msg_index[$MESSAGE->index-1]) : -1 ;
+    $first = count($a_msg_index)>0 ? $IMAP->get_uid($a_msg_index[0]) : -1;
+    $next = isset($a_msg_index[$MESSAGE->index+1]) ? $IMAP->get_uid($a_msg_index[$MESSAGE->index+1]) : -1 ;
+    $last = count($a_msg_index)>0 ? $IMAP->get_uid($a_msg_index[count($a_msg_index)-1]) : -1;
     }
   else
     {
@@ -130,11 +131,11 @@
   
   if ($prev > 0)
     $OUTPUT->set_env('prev_uid', $prev);
-  if ($first >0)
+  if ($first > 0)
     $OUTPUT->set_env('first_uid', $first);
   if ($next > 0)
     $OUTPUT->set_env('next_uid', $next);
-  if ($last >0)
+  if ($last > 0)
     $OUTPUT->set_env('last_uid', $last);
 
   // mark message as read
diff --git a/skins/default/common.css b/skins/default/common.css
index 2029bf7..1225862 100644
--- a/skins/default/common.css
+++ b/skins/default/common.css
@@ -328,7 +328,7 @@
 #quicksearchbar
 {
   position: absolute;
-  top: 60px;
+  top: 55px;
   right: 20px;
   width: 182px;
   height: 20px;
diff --git a/skins/default/mail.css b/skins/default/mail.css
index 474a77f..5189f6d 100644
--- a/skins/default/mail.css
+++ b/skins/default/mail.css
@@ -4,7 +4,7 @@
 #messagetoolbar
 {
   position: absolute;
-  top: 45px;
+  top: 47px;
   left: 200px;
   right: 200px;
   height: 35px;
@@ -24,11 +24,17 @@
   color: #333333;
 }
 
+#messagetoolbar select.searchfilter
+{
+  position: relative;
+  bottom: 10px;
+}
+
 #messagetoolbar select.mboxlist
 {
   position: absolute;
   left: 375px;
-  top: 10px;
+  top: 8px;
 }
 
 #messagetoolbar select.mboxlist option
diff --git a/skins/default/templates/mail.html b/skins/default/templates/mail.html
index 43ff43b..51e1b1f 100644
--- a/skins/default/templates/mail.html
+++ b/skins/default/templates/mail.html
@@ -118,6 +118,7 @@
 <roundcube:button command="forward" imageSel="/images/buttons/forward_sel.png" imageAct="/images/buttons/forward_act.png" imagePas="/images/buttons/forward_pas.png" width="32" height="32" title="forwardmessage" />
 <roundcube:button command="delete" imageSel="/images/buttons/delete_sel.png" imageAct="/images/buttons/delete_act.png" imagePas="/images/buttons/delete_pas.png" width="32" height="32" title="deletemessage" />
 <roundcube:button command="print" imageSel="/images/buttons/print_sel.png" imageAct="/images/buttons/print_act.png" imagePas="/images/buttons/print_pas.png" width="32" height="32" title="printmessage" />
+<roundcube:object name="searchfilter" id="searchfilter" class="searchfilter" />
 
 <div id="markmessagemenu">
   <ul class="toolbarmenu">

--
Gitblit v1.9.1