From 4647e1bbb5beba82605695c4dc989ca867e53244 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Thu, 23 Mar 2006 17:32:47 -0500
Subject: [PATCH] Started implementing search function

---
 CHANGELOG                               |    8 +
 program/include/main.inc                |   26 ++-
 skins/default/mail.css                  |   29 +++
 program/lib/imap.inc                    |   17 +
 program/localization/de_CH/labels.inc   |    7 
 config/main.inc.php.dist                |    6 
 skins/default/images/icons/reset.gif    |    0 
 program/steps/mail/sendmail.inc         |   11 +
 program/steps/settings/save_prefs.inc   |    1 
 program/localization/de_DE/labels.inc   |    7 
 index.php                               |    5 
 program/steps/mail/list.inc             |   24 ++
 skins/default/templates/mail.html       |    4 
 program/localization/en_US/messages.inc |    6 
 program/steps/mail/func.inc             |   53 +++++
 program/steps/settings/func.inc         |    9 +
 program/localization/en_US/labels.inc   |    6 
 program/js/app.js                       |   46 +++++
 program/include/rcube_imap.inc          |  171 ++++++++++++++++++--
 19 files changed, 383 insertions(+), 53 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index da1f9a7..cba9184 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,14 @@
 CHANGELOG RoundCube Webmail
 ---------------------------
 
+2006/03/23
+----------
+- Auto-detect mail header delimiters
+- Regard daylight savings
+- Localized quota display
+- Started implementing search function
+
+
 2006/03/20
 ----------
 - Avoid error message when saving an unchanged identity (Bug #1429510)
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 4261102..55a84f6 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -138,7 +138,8 @@
 $rcmail_config['generic_message_footer'] = '';
 
 // this string is used as a delimiter for message headers when sending
-$rcmail_config['mail_header_delimiter'] = "\r\n";
+// leave empty for auto-detection
+$rcmail_config['mail_header_delimiter'] = NULL;
 
 // in order to enable public ldap search, create a config array
 // like the Verisign example below. if you would like to test, 
@@ -165,6 +166,9 @@
 // use this timezone to display date/time
 $rcmail_config['timezone'] = 1;
 
+// daylight savings are On
+$rcmail_config['dst_active'] = TRUE;
+
 // prefer displaying HTML messages
 $rcmail_config['prefer_html'] = TRUE;
 
diff --git a/index.php b/index.php
index 72a6826..8a98af6 100644
--- a/index.php
+++ b/index.php
@@ -266,9 +266,12 @@
   if ($_action=='getunread')
     include('program/steps/mail/getunread.inc');
     
-  if ($_action=='list' && $_GET['_remote'])
+  if ($_action=='list' && isset($_GET['_remote']))
     include('program/steps/mail/list.inc');
 
+   if ($_action=='search')
+     include('program/steps/mail/search.inc'); 
+
   if ($_action=='rss')
     include('program/steps/mail/rss.inc');
 
diff --git a/program/include/main.inc b/program/include/main.inc
index d3ee5e9..0d1b27e 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -613,13 +613,13 @@
   }
 
 
-function show_message($message, $type='notice')
+function show_message($message, $type='notice', $vars=NULL)
   {
   global $OUTPUT, $JS_OBJECT_NAME, $REMOTE_REQUEST;
-
+  
   $framed = $GLOBALS['_framed'];
   $command = sprintf("display_message('%s', '%s');",
-                     addslashes(rep_specialchars_output(rcube_label($message))),
+                     addslashes(rep_specialchars_output(rcube_label(array('name' => $message, 'vars' => $vars)))),
                      $type);
                      
   if ($REMOTE_REQUEST)
@@ -1099,6 +1099,7 @@
         'composeattachment' => 'rcmail_compose_attachment_field',
         'priorityselector' => 'rcmail_priority_selector',
         'charsetselector' => 'rcmail_charset_selector',
+        'searchform' => 'rcmail_search_form',
         
         // ADDRESS BOOK
         'addresslist' => 'rcmail_contacts_list',
@@ -1416,25 +1417,30 @@
   {
   global $CONFIG, $sess_user_lang;
   
+  $ts = NULL;
+  
   if (is_numeric($date))
     $ts = $date;
   else if (!empty($date))
-    $ts = strtotime($date);
-  else
+    $ts = @strtotime($date);
+    
+  if (empty($ts))
     return '';
+   
+  // get user's timezone
+  $tz = $CONFIG['timezone'];
+  if ($CONFIG['dst_active'])
+    $tz++;
 
   // convert time to user's timezone
-  $timestamp = $ts - date('Z', $ts) + ($CONFIG['timezone'] * 3600);
+  $timestamp = $ts - date('Z', $ts) + ($tz * 3600);
   
   // get current timestamp in user's timezone
   $now = time();  // local time
   $now -= (int)date('Z'); // make GMT time
-  $now += ($CONFIG['timezone'] * 3600); // user's time
+  $now += ($tz * 3600); // user's time
   $now_date = getdate();
 
-  //$day_secs = 60*((int)date('H', $now)*60 + (int)date('i', $now));
-  //$week_secs = 60 * 60 * 24 * 7;
-  //$diff = $now - $timestamp;
   $today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']);
   $week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']);
 
diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc
index 143b17b..ebca1dd 100644
--- a/program/include/rcube_imap.inc
+++ b/program/include/rcube_imap.inc
@@ -98,7 +98,7 @@
    */
   function connect($host, $user, $pass, $port=143, $use_ssl=FALSE)
     {
-    global $ICL_SSL, $ICL_PORT;
+    global $ICL_SSL, $ICL_PORT, $IMAP_USE_INTERNAL_DATE;
     
     // check for Open-SSL support in PHP build
     if ($use_ssl && in_array('openssl', get_loaded_extensions()))
@@ -111,6 +111,8 @@
       }
 
     $ICL_PORT = $port;
+    $IMAP_USE_INTERNAL_DATE = false;
+    
     $this->conn = iil_Connect($host, $user, $pass, array('imap' => 'check'));
     $this->host = $host;
     $this->user = $user;
@@ -475,7 +477,7 @@
 
 
   /**
-   * Private method for listing message header
+   * Private method for listing message headers
    *
    * @access  private
    * @see     rcube_imap::list_headers
@@ -493,6 +495,9 @@
     $max = $this->_messagecount($mailbox);
     $start_msg = ($this->list_page-1) * $this->page_size;
     
+    list($begin, $end) = $this->_get_message_range($max, $page);
+    
+    /*    
     if ($page=='all')
       {
       $begin = 0;
@@ -512,7 +517,8 @@
     if ($begin < 0) $begin = 0;
     if ($end < 0) $end = $max;
     if ($end > $max) $end = $max;
-
+	*/
+	
 //console("fetch headers $start_msg to ".($start_msg+$this->page_size)." (msg $begin to $end)");
 
     $headers_sorted = FALSE;
@@ -536,12 +542,7 @@
         
         $msgs = $msg_index[$begin];
         for ($i=$begin+1; $i < $end; $i++)
-          {
-          //if ($this->sort_order == 'DESC')
-          //  $msgs = $msg_index[$i].','.$msgs;
-          //else
-            $msgs = $msgs.','.$msg_index[$i];
-          }
+          $msgs = $msgs.','.$msg_index[$i];
 
         $sorted = TRUE;
         }
@@ -585,14 +586,111 @@
 
     return array_values($a_msg_headers);
     }
+    
 
+  /**
+   * Public method for listing a specific set of headers
+   * convert mailbox name with root dir first
+   *
+   * @param   string   Mailbox/folder name
+   * @param   array    List of message ids to list
+   * @param   number   Current page to list
+   * @param   string   Header field to sort by
+   * @param   string   Sort order [ASC|DESC]
+   * @return  array    Indexed array with message header objects
+   * @access  public   
+   */
+  function list_header_set($mbox='', $msgs, $page=NULL, $sort_field=NULL, $sort_order=NULL)
+    {
+    $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
+    return $this->_list_header_set($mailbox, $msgs, $page, $sort_field, $sort_order);    
+    }
+    
+
+  /**
+   * Private method for listing a set of message headers
+   *
+   * @access  private
+   * @see     rcube_imap::list_header_set
+   */
+  function _list_header_set($mailbox, $msgs, $page=NULL, $sort_field=NULL, $sort_order=NULL)
+    {
+    // also accept a comma-separated list of message ids
+    if (is_string($msgs))
+      $msgs = split(',', $msgs);
+      
+    if (!strlen($mailbox) || empty($msgs))
+      return array();
+
+    if ($sort_field!=NULL)
+      $this->sort_field = $sort_field;
+    if ($sort_order!=NULL)
+      $this->sort_order = strtoupper($sort_order);
+
+    $max = count($msgs);
+    $start_msg = ($this->list_page-1) * $this->page_size;
+    
+    list($begin, $end) = $this->_get_message_range($max, $page);
+
+    // fetch reuested headers from server
+    $a_msg_headers = array();
+    $this->_fetch_headers($mailbox, join(',', $msgs), $a_msg_headers, NULL);
+
+    // return empty array if no messages found
+	if (!is_array($a_msg_headers) || empty($a_msg_headers))
+		return array();
+
+    // if not already sorted
+    $a_msg_headers = iil_SortHeaders($a_msg_headers, $this->sort_field, $this->sort_order);
+
+	// only return the requested part of the set
+	return array_slice(array_values($a_msg_headers), $begin, min($max, $this->page_size));
+    }
+
+
+  /**
+   * Helper function to get first and last index of the requested set
+   *
+   * @param  number  message count
+   * @param  mixed   page number to show, or string 'all'
+   * @return array   array with two values: first index, last index
+   * @access private
+   */
+  function _get_message_range($max, $page)
+    {
+    $start_msg = ($this->list_page-1) * $this->page_size;
+    
+    if ($page=='all')
+      {
+      $begin = 0;
+      $end = $max;
+      }
+    else if ($this->sort_order=='DESC')
+      {
+      $begin = $max - $this->page_size - $start_msg;
+      $end =   $max - $start_msg;
+      }
+    else
+      {
+      $begin = $start_msg;
+      $end   = $start_msg + $this->page_size;
+      }
+
+    if ($begin < 0) $begin = 0;
+    if ($end < 0) $end = $max;
+    if ($end > $max) $end = $max;
+    
+    return array($begin, $end);
+    }
+    
+    
 
   /**
    * Fetches message headers
    * Used for loop
    *
    * @param  string  Mailbox name
-   * @param  string  Message indey to fetch
+   * @param  string  Message index to fetch
    * @param  array   Reference to message headers array
    * @param  array   Array with cache index
    * @return number  Number of deleted messages
@@ -602,7 +700,7 @@
     {
     // cache is incomplete
     $cache_index = $this->get_message_cache_index($cache_key);
-
+    
     // fetch reuested headers from server
     $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, $msgs);
     $deleted_count = 0;
@@ -746,16 +844,44 @@
     }
 
 
-  function search($mbox='', $criteria='ALL')
+  /**
+   * 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
+   * @return array   search results as list of message ids
+   * @access public
+   */
+  function search($mbox='', $criteria='ALL', $str=NULL)
     {
     $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
-    return $this->_search_index($mailbox, $criteria);
-    }
-    
-    
+    if ($str && $criteria)
+      {
+      $criteria .= " \"$str\"";
+      return $this->_search_index($mailbox, $criteria);
+      }
+    else
+      return $this->_search_index($mailbox, $criteria);
+    }    
+
+
+  /**
+   * Private search method
+   *
+   * @return array   search results as list of message ids
+   * @access private
+   * @see rcube_imap::search()
+   */
   function _search_index($mailbox, $criteria='ALL')
     {
     $a_messages = iil_C_Search($this->conn, $mailbox, $criteria);
+    
+    // clean message list (there might be some empty entries)
+    foreach ($a_messages as $i => $val)
+      if (empty($val))
+        unset($a_messages[$i]);
+        
     return $a_messages;
     }
 
@@ -1070,10 +1196,11 @@
     if ($this->get_capability('QUOTA'))
       {
       $result = iil_C_GetQuota($this->conn);
-      return sprintf("%.2fMB / %.2fMB (%.0f%%)", $result["used"] / 1000.0, $result["total"] / 1000.0, $result["percent"]);
+      if ($result["total"])
+        return sprintf("%.2fMB / %.2fMB (%.0f%%)", $result["used"] / 1000.0, $result["total"] / 1000.0, $result["percent"]);       
       }
-    else
-      return 'unknown';
+
+    return FALSE;
     }
 
 
@@ -1444,6 +1571,10 @@
     {
     static $sa_message_index = array();
     
+    // empty key -> empty array
+    if (empty($key))
+      return array();
+    
     if (!empty($sa_message_index[$key]) && !$force)
       return $sa_message_index[$key];
     
@@ -1466,7 +1597,7 @@
 
   function add_message_cache($key, $index, $headers)
     {
-    if (!is_object($headers) || empty($headers->uid))
+    if (!$key || !is_object($headers) || empty($headers->uid))
       return;
 
     $this->db->query(
diff --git a/program/js/app.js b/program/js/app.js
index 4713788..81eaef3 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -122,7 +122,7 @@
           }
 
         // enable mail commands
-        this.enable_command('list', 'compose', 'add-contact', true);
+        this.enable_command('list', 'compose', 'add-contact', 'search', 'reset-search', true);
         
         if (this.env.action=='show')
           {
@@ -574,7 +574,11 @@
       // misc list commands
       case 'list':
         if (this.task=='mail')
+          {
+          if (this.env.search_request && props != this.env.mailbox)
+            this.reset_qsearch();
           this.list_mailbox(props);
+          }
         else if (this.task=='addressbook')
           this.list_contacts();
         break;
@@ -904,6 +908,22 @@
         this.add_contact(props);
         break;
       
+      // mail quicksearch
+      case 'search':
+        if (!props && this.gui_objects.qsearchbox)
+          props = this.gui_objects.qsearchbox.value;
+        if (props)
+          this.qsearch(escape(props), this.env.mailbox);
+        break;
+
+      // reset quicksearch        
+      case 'reset-search':
+        var s = this.env.search_request;
+        this.reset_qsearch();
+        
+        if (s)
+          this.list_mailbox(this.env.mailbox);
+        break;
 
       // ldap search
       case 'ldappublicsearch':
@@ -1368,6 +1388,10 @@
       this.env.current_page = page;
       this.clear_selection();
       }
+    
+    // also send search request to get the right messages
+    if (this.env.search_request)
+      add_url += '&_search='+this.env.search_request;
       
     if (this.env.mailbox!=mbox)
       this.select_mailbox(mbox);
@@ -1803,6 +1827,26 @@
       this.http_request('addcontact', '_address='+value);
     };
 
+  // send remote request to search mail
+  this.qsearch = function(value, mbox)
+    {
+    if (value && mbox)
+      {
+      this.clear_message_list();
+      this.set_busy(true, 'searching');
+      this.http_request('search', '_search='+value+'&_mbox='+mbox, true);
+      }
+    };
+
+  // reset quick-search form
+  this.reset_qsearch = function()
+    {
+    if (this.gui_objects.qsearchbox)
+      this.gui_objects.qsearchbox.value = '';
+      
+    this.env.search_request = null;
+    };
+    
 
   /*********************************************************/
   /*********     keyboard live-search methods      *********/
diff --git a/program/lib/imap.inc b/program/lib/imap.inc
index bef2de9..73eb970 100644
--- a/program/lib/imap.inc
+++ b/program/lib/imap.inc
@@ -39,6 +39,7 @@
 		- Added BCC and REFERENCE to the list of headers to fetch in iil_C_FetchHeaders()
 		- Leave messageID unchanged in iil_C_FetchHeaders()
 		- Avoid stripslahes in iil_Connect()
+		- Added patch to iil_SortHeaders() by Richard Green
 		- Removed <br> from error messages (better for logging)
 		- Removed some debuggers (echo ...)
 
@@ -1396,7 +1397,7 @@
 	if (empty($flag)) $flag="ASC";
 	$flag=strtoupper($flag);
 	$stripArr = ($field=='subject') ? array('Re: ','Fwd: ','Fw: ',"\"") : array("\"");
-	
+
 	$c=count($a);
 	if ($c>0){
 		/*
@@ -1410,8 +1411,18 @@
 		$index=array();
 		reset($a);
 		while (list($key, $val)=each($a)){
-			$data=$a[$key]->$field;
-			if (is_string($data)) $data=strtoupper(str_replace($stripArr, "", $data));
+
+			if ($field=="timestamp"){
+				$data = @strtotime($value->date);
+				if ($data != false)
+					$data = $timestamp;
+				}
+			else {
+				$data=$a[$key]->$field;
+				if (is_string($data))
+					$data=strtoupper(str_replace($stripArr, "", $data));
+				}
+
 			$index[$key]=$data;
 		}
 		
diff --git a/program/localization/de_CH/labels.inc b/program/localization/de_CH/labels.inc
index e5805f9..1ea36f0 100644
--- a/program/localization/de_CH/labels.inc
+++ b/program/localization/de_CH/labels.inc
@@ -111,6 +111,12 @@
 $labels['purge'] = 'Aufräumen';
 
 $labels['quota'] = 'Verwendeter Speicherplatz';
+$labels['unknown']  = 'unbekannt';
+$labels['unlimited']  = 'unlimitiert';
+
+$labels['quicksearch']  = 'Schnellsuche';
+$labels['resetsearch']  = 'Löschen';
+
 
 // message compose // Nachrichten erstellen
 $labels['compose']  = 'Neue Nachricht verfassen';
@@ -182,6 +188,7 @@
 $labels['timezone']  = 'Zeitzone';
 $labels['pagesize']  = 'Einträge pro Seite';
 $labels['signature'] = 'Signatur';
+$labels['dstactive']  = 'Sommerzeit';
 
 $labels['folder']  = 'Ordner';
 $labels['folders']  = 'Ordner';
diff --git a/program/localization/de_DE/labels.inc b/program/localization/de_DE/labels.inc
index d21caab..9f9c121 100644
--- a/program/localization/de_DE/labels.inc
+++ b/program/localization/de_DE/labels.inc
@@ -112,6 +112,12 @@
 $labels['purge'] = 'Bereinigen';
 
 $labels['quota'] = 'Verwendeter Speicherplatz';
+$labels['unknown']  = 'unbekannt';
+$labels['unlimited']  = 'unlimitiert';
+
+$labels['quicksearch']  = 'Schnellsuche';
+$labels['resetsearch']  = 'Löschen';
+
 
 // message compose // Nachrichten erstellen
 $labels['compose']  = 'Neue Nachricht verfassen';
@@ -183,6 +189,7 @@
 $labels['timezone']  = 'Zeitzone';
 $labels['pagesize']  = 'Einträge pro Seite';
 $labels['signature'] = 'Signatur';
+$labels['dstactive']  = 'Sommerzeit';
 
 $labels['folder']  = 'Ordner';
 $labels['folders']  = 'Ordner';
diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc
index 015e12c..3e3e57d 100644
--- a/program/localization/en_US/labels.inc
+++ b/program/localization/en_US/labels.inc
@@ -111,6 +111,11 @@
 $labels['purge'] = 'Purge';
 
 $labels['quota'] = 'Disk usage';
+$labels['unknown']  = 'unknown';
+$labels['unlimited']  = 'unlimited';
+
+$labels['quicksearch']  = 'Quick search';
+$labels['resetsearch']  = 'Reset search';
 
 
 // message compose
@@ -185,6 +190,7 @@
 $labels['timezone']  = 'Time zone';
 $labels['pagesize']  = 'Rows per page';
 $labels['signature'] = 'Signature';
+$labels['dstactive']  = 'Daylight savings';
 
 $labels['folder']  = 'Folder';
 $labels['folders']  = 'Folders';
diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc
index a689368..820d1b5 100644
--- a/program/localization/en_US/messages.inc
+++ b/program/localization/en_US/messages.inc
@@ -88,4 +88,10 @@
 
 $messages['nosearchname'] = 'Please enter a contact name or email address';
 
+$messages['searchsuccessful'] = '$nr messages found';
+
+$messages['searchnomatch'] = 'Search returned no matches';
+
+$messages['searching'] = 'Searching...';
+
 ?>
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 418c52b..a6f8b3f 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -528,6 +528,36 @@
   }
 
 
+// return code for search function
+function rcmail_search_form($attrib)
+  {
+  global $OUTPUT, $JS_OBJECT_NAME;
+
+  // add some labels to client
+  rcube_add_label('searching');
+
+  $attrib['name'] = '_q';
+  
+  if (empty($attrib['id']))
+    $attrib['id'] = 'rcmqsearchbox';
+  
+  $input_q = new textfield($attrib);
+  $out = $input_q->show();
+
+  $OUTPUT->add_script(sprintf("%s.gui_object('qsearchbox', '%s');",
+                              $JS_OBJECT_NAME,
+                              $attrib['id']));
+
+  // add form tag around text field
+  if (empty($attrib['form']))
+    $out = sprintf('<form name="rcmqsearchform" action="./" '.
+                   'onsubmit="%s.command(\'search\');return false" style="display:inline;">%s</form>',
+                   $JS_OBJECT_NAME,
+                   $out);
+
+  return $out;
+  } 
+
 
 function rcmail_messagecount_display($attrib)
   {
@@ -536,7 +566,9 @@
   if (!$attrib['id'])
     $attrib['id'] = 'rcmcountdisplay';
 
-  $OUTPUT->add_script(sprintf("%s.gui_object('countdisplay', '%s');", $JS_OBJECT_NAME, $attrib['id']));
+  $OUTPUT->add_script(sprintf("%s.gui_object('countdisplay', '%s');",
+                              $JS_OBJECT_NAME,
+                              $attrib['id']));
 
   // allow the following attributes to be added to the <span> tag
   $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
@@ -560,16 +592,20 @@
 
   // allow the following attributes to be added to the <span> tag
   $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
-
+  
+  if (!$IMAP->get_capability('QUOTA'))
+    $quota_text = rcube_label('unknown');
+  else if (!($quota_text = $IMAP->get_quota()))
+    $quota_text = rcube_label('unlimited');
 
   $out = '<span' . $attrib_str . '>';
-  $out .= $IMAP->get_quota();
+  $out .= $quota_text;
   $out .= '</span>';
   return $out;
   }
 
 
-function rcmail_get_messagecount_text()
+function rcmail_get_messagecount_text($count=NULL, $page=NULL)
   {
   global $IMAP, $MESSAGE;
   
@@ -577,11 +613,14 @@
     {
     return rcube_label(array('name' => 'messagenrof',
                              'vars' => array('nr'  => $MESSAGE['index']+1,
-                                             'count' => $IMAP->messagecount())));
+                                             'count' => $count!==NULL ? $count : $IMAP->messagecount())));
     }
 
-  $start_msg = ($IMAP->list_page-1) * $IMAP->page_size + 1;
-  $max = $IMAP->messagecount();
+  if ($page===NULL)
+    $page = $IMAP->list_page;
+    
+  $start_msg = ($page-1) * $IMAP->page_size + 1;
+  $max = $count!==NULL ? $count : $IMAP->messagecount();
 
   if ($max==0)
     $out = rcube_label('mailboxempty');
diff --git a/program/steps/mail/list.inc b/program/steps/mail/list.inc
index 391c05b..40cd652 100644
--- a/program/steps/mail/list.inc
+++ b/program/steps/mail/list.inc
@@ -22,8 +22,6 @@
 $REMOTE_REQUEST = TRUE;
 $OUTPUT_TYPE = 'js';
 
-$unseen = $IMAP->messagecount($mbox, 'UNSEEN', !empty($_GET['_refresh']) ? TRUE : FALSE);
-$count = $IMAP->messagecount();
 $sort = isset($_GET['_sort']) ? $_GET['_sort'] : false;
 
 // is there a sort type for this request?
@@ -37,12 +35,27 @@
   $_SESSION['sort_order'] = $sort_order;
   }
 else
-  {        
+  {
   // use session settings if set, defaults if not
   $sort_col   = isset($_SESSION['sort_col'])   ? $_SESSION['sort_col']   : $CONFIG['message_sort_col'];
   $sort_order = isset($_SESSION['sort_order']) ? $_SESSION['sort_order'] : $CONFIG['message_sort_order'];
   }
   
+
+// we have a saved search request
+if (!empty($_GET['_search']) && isset($_SESSION['search'][$_GET['_search']]))
+  {
+  $a_msgs = split(',', $_SESSION['search'][$_GET['_search']]);
+  $a_headers = $IMAP->list_header_set($mbox, $a_msgs, NULL, $sort_col, $sort_order);
+  $count = count($a_msgs);
+  }
+else
+  {
+  if ($count = $IMAP->messagecount())
+    $a_headers = $IMAP->list_headers($mbox, NULL, $sort_col, $sort_order);
+  }
+
+$unseen = $IMAP->messagecount($mbox, 'UNSEEN', !empty($_GET['_refresh']) ? TRUE : FALSE);
 
 // update message count display
 $pages = ceil($count/$IMAP->page_size);
@@ -56,11 +69,8 @@
 
 
 // add message rows
-if ($count)
-  {
-  $a_headers = $IMAP->list_headers($mbox, null, $sort_col, $sort_order);
+if (isset($a_headers) && count($a_headers))
   $commands .= rcmail_js_message_list($a_headers);
-  }
 
   
 // send response
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index 70baba0..33f023d 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -159,9 +159,16 @@
     }
   }
 
-
+// try to autodetect operating system and use the correct line endings
 // use the configured delimiter for headers
-$header_delm = $CONFIG['mail_header_delimiter'] ? $CONFIG['mail_header_delimiter'] : "\r\n";
+if (!empty($CONFIG['mail_header_delimiter']))
+  $header_delm = $CONFIG['mail_header_delimiter'];
+else if (strtolower(substr(PHP_OS, 0, 3)=='win')) 
+  $header_delm = "\r\n";
+else if (strtolower(substr(PHP_OS, 0, 3)=='mac'))
+  $header_delm = "\r\n";
+else    
+  $header_delm = "\n";
 
 // create PEAR::Mail_mime instance
 $MAIL_MIME = new Mail_mime($header_delm);
diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc
index ccc7871..a22ac9a 100644
--- a/program/steps/settings/func.inc
+++ b/program/steps/settings/func.inc
@@ -78,6 +78,7 @@
   $select_timezone->add('(GMT -5:00) Eastern Time (US/Canada), Bogota, Lima', '-5');
   $select_timezone->add('(GMT -4:00) Atlantic Time (Canada), Caracas, La Paz', '-4');
   $select_timezone->add('(GMT -3:00) Brazil, Buenos Aires, Georgetown', '-3');
+  $select_timezone->add('(GMT -3:30) Nfld Time (Canada), Nfld, S. Labador', '-3.5');
   $select_timezone->add('(GMT -2:00) Mid-Atlantic', '-2');
   $select_timezone->add('(GMT -1:00) Azores, Cape Verde Islands', '-1');
   $select_timezone->add('(GMT) Western Europe, London, Lisbon, Casablanca', '0');
@@ -108,6 +109,14 @@
                   $select_timezone->show($CONFIG['timezone']));
 
 
+  $field_id = 'rcmfd_dst';
+  $input_dst = new checkbox(array('name' => '_dst_active', 'id' => $field_id, 'value' => 1));
+  $out .= sprintf("<tr><td class=\"title\"><label for=\"%s\">%s</label></td><td>%s</td></tr>\n",
+                  $field_id,
+                  rep_specialchars_output(rcube_label('dstactive')),
+                  $input_dst->show($CONFIG['dst_active']));
+
+
   // show page size selection
   $field_id = 'rcmfd_pgsize';
   $input_pagesize = new textfield(array('name' => '_pagesize', 'id' => $field_id, 'size' => 5));
diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc
index d78acbd..81ffbe8 100644
--- a/program/steps/settings/save_prefs.inc
+++ b/program/steps/settings/save_prefs.inc
@@ -25,6 +25,7 @@
 
 
 $a_user_prefs['timezone'] = isset($_POST['_timezone']) ? floatval($_POST['_timezone']) : $CONFIG['timezone'];
+$a_user_prefs['dst_active'] = isset($_POST['_dst_active']) ? TRUE : FALSE;
 $a_user_prefs['pagesize'] = is_numeric($_POST['_pagesize']) ? (int)$_POST['_pagesize'] : $CONFIG['pagesize'];
 $a_user_prefs['prefer_html'] = isset($_POST['_prefer_html']) ? TRUE : FALSE;
 
diff --git a/skins/default/images/icons/reset.gif b/skins/default/images/icons/reset.gif
new file mode 100644
index 0000000..1bdbc5b
--- /dev/null
+++ b/skins/default/images/icons/reset.gif
Binary files differ
diff --git a/skins/default/mail.css b/skins/default/mail.css
index 9a604b4..1f781ba 100644
--- a/skins/default/mail.css
+++ b/skins/default/mail.css
@@ -82,7 +82,7 @@
 #messagecountbar
 {
   position: absolute;
-  top: 60px;
+  bottom: 16px;
   right: 40px;
   width: 300px;
   height: 20px;
@@ -457,6 +457,33 @@
   color: #CCCCCC;
 }
 
+#quicksearchbar
+{
+  position: absolute;
+  top: 60px;
+  right: 40px;
+  width: 200px;
+  height: 20px;
+  text-align: right;
+}
+
+#quicksearchbar a
+{
+  text-decoration: none;
+  padding-left: 5px;
+}
+
+#quicksearchbar img
+{
+  vertical-align: middle;
+}
+
+#quicksearchbox
+{
+  width: 150px;
+  border: 1px solid #999999;
+}
+
 
 /** message view styles */
 
diff --git a/skins/default/templates/mail.html b/skins/default/templates/mail.html
index 224668e..7e5d447 100644
--- a/skins/default/templates/mail.html
+++ b/skins/default/templates/mail.html
@@ -19,6 +19,10 @@
 <roundcube:button command="print" imageAct="/images/buttons/print_act.png" imagePas="/images/buttons/print_pas.png" width="32" height="32" title="printmessage" />
 </div>
 
+<div id="quicksearchbar">
+<roundcube:object name="searchform" id="quicksearchbox" /><roundcube:button command="reset-search" image="/images/icons/reset.gif" title="resetsearch" />
+</div>
+
 <div id="messagecountbar">
 <roundcube:button command="previouspage" imageAct="/images/buttons/previous_act.png" imagePas="/images/buttons/previous_pas.png" width="11" height="11" title="previousmessages" />
 &nbsp;<roundcube:object name="messageCountDisplay" />&nbsp;

--
Gitblit v1.9.1