From 43fa235da354c8b53aa69ba745c1d398a758fcaf Mon Sep 17 00:00:00 2001
From: svncommit <devs@roundcube.net>
Date: Wed, 26 Oct 2005 05:42:19 -0400
Subject: [PATCH] 

---
 program/include/rcube_imap.inc |  359 +++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 282 insertions(+), 77 deletions(-)

diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc
index b5eba00..47999c8 100644
--- a/program/include/rcube_imap.inc
+++ b/program/include/rcube_imap.inc
@@ -23,19 +23,19 @@
 
 require_once('lib/imap.inc');
 require_once('lib/mime.inc');
+require_once('lib/utf7.inc');
 
-// check for Open-SSL support in PHP build
-//$ICL_SSL = TRUE;
-//$ICL_PORT = 993;
 
 class rcube_imap
   {
   var $conn;
+  var $root_ns = '';
   var $root_dir = '';
   var $mailbox = 'INBOX';
   var $list_page = 1;
   var $page_size = 10;
-  var $cacheing_enabled = FALSE;
+  var $delimiter = NULL;
+  var $caching_enabled = FALSE;
   var $default_folders = array('inbox', 'drafts', 'sent', 'junk', 'trash');
   var $cache = array();
   var $cache_changes = array();  
@@ -46,8 +46,7 @@
   // PHP 5 constructor
   function __construct()
     {
-    if (function_exists('rcube_read_cache'))
-      $this->cacheing_enabled = TRUE;
+    
     }
 
   // PHP 4 compatibility
@@ -57,33 +56,55 @@
     }
 
 
-  function iloha_imap($connection='')
+  function connect($host, $user, $pass, $port=143, $use_ssl=FALSE)
     {
-    if ($connection)
+    global $ICL_SSL, $ICL_PORT, $CONFIG;
+    
+    // check for Open-SSL support in PHP build
+    if ($use_ssl && in_array('openssl', get_loaded_extensions()))
+      $ICL_SSL = TRUE;
+    else if ($use_ssl)
       {
-      $a_url = parse_url($connection);
-      $scheme = $a_url['scheme'] ? $a_url['scheme'] : 'imap';
-      $port = $a_url['port'] ? $a_url['port'] : ($scheme=='imaps' ? 993 : 143);
-      $host = $a_url['host'];
-      $user = $a_url['user'];
-      $pass = $a_url['pass'];
-      
-      //var_dump($a_url);
-      
-      $this->connect($host, $user, $pass, $port);
+      raise_error(array('code' => 403,
+                        'type' => 'imap',
+                        'file' => __FILE__,
+                        'message' => 'Open SSL not available;'), TRUE, FALSE);
+      $port = 143;
       }
-    }
-
-
-  function connect($host, $user, $pass, $port=143)
-    {
-    global $ICL_PORT;
 
     $ICL_PORT = $port;
-    $this->conn = iil_Connect($host, $user, $pass);
+    $this->conn = iil_Connect($host, $user, $pass, array('imap' => 'check'));
     $this->host = $host;
     $this->user = $user;
     $this->pass = $pass;
+    $this->port = $port;
+    $this->ssl = $use_ssl;
+    
+    // print trace mesages
+    if ($this->conn && ($CONFIG['debug_level'] & 8))
+      console($this->conn->message);
+    
+    // write error log
+    else if (!$this->conn && $GLOBALS['iil_error'])
+      {
+      raise_error(array('code' => 403,
+                       'type' => 'imap',
+                       'message' => $GLOBALS['iil_error']), TRUE, FALSE);
+      }
+
+    // get account namespace
+    if ($this->conn)
+      {
+      iil_C_NameSpace($this->conn);
+      
+      if (!empty($this->conn->delimiter))
+        $this->delimiter = $this->conn->delimiter;
+      if (!empty($this->conn->rootdir))
+        {
+        $this->set_rootdir($this->conn->rootdir);
+        $this->root_ns = ereg_replace('[\.\/]$', '', $this->conn->rootdir);
+        }
+      }
 
     return $this->conn ? TRUE : FALSE;
     }
@@ -96,12 +117,22 @@
     }
 
 
+  function reconnect()
+    {
+    $this->close();
+    $this->connect($this->host, $this->user, $this->pass, $this->port, $this->ssl);
+    }
+
+
   function set_rootdir($root)
     {
-    if (substr($root, -1, 1)==='/')
+    if (ereg('[\.\/]$', $root)) //(substr($root, -1, 1)==='/')
       $root = substr($root, 0, -1);
 
     $this->root_dir = $root;
+    
+    if (empty($this->delimiter))
+      $this->get_hierarchy_delimiter();
     }
 
 
@@ -153,6 +184,17 @@
     return $this->conn ? $this->_mod_mailbox($this->mailbox, 'out') : '';
     }
 
+
+  function get_hierarchy_delimiter()
+    {
+    if ($this->conn && empty($this->delimiter))
+      $this->delimiter = iil_C_GetHierarchyDelimiter($this->conn);
+
+    if (empty($this->delimiter))
+      $this->delimiter = '/';
+
+    return $this->delimiter;
+    }
 
   // public method for mailbox listing
   // convert mailbox name with root dir first
@@ -234,8 +276,6 @@
     else
       $count = iil_C_CountMessages($this->conn, $mailbox);
 
-//print "/**** get messagecount for $mailbox ($mode): $count ****/\n";
-
     if (is_array($a_mailbox_cache[$mailbox]))
       $a_mailbox_cache[$mailbox] = array();
       
@@ -243,8 +283,6 @@
     
     // write back to cache
     $this->update_cache('messagecount', $a_mailbox_cache);
-
-//var_dump($a_mailbox_cache);
 
     return (int)$count;
     }
@@ -260,45 +298,132 @@
 
 
   // private method for listing message header
-  function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
+  // by DrSlump <drslump@drslump.biz>
+  function __list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
     {
-    $max = $this->_messagecount($mailbox /*, 'ALL', TRUE*/);
     $a_out = array();
-    
+    $cached_count = 0;
+
     if (!strlen($mailbox))
       return $a_out;
 
+    $mbox_count = $this->_messagecount($mailbox /*, 'ALL', TRUE*/);
 
-    // get cached headers
-    $a_msg_headers = $this->get_cache($mailbox.'.msg');
-
-// print "/**** count = $max; headers = ".sizeof($a_msg_headers)." ****/\n";
-
-    // retrieve headers from IMAP
-    if (!is_array($a_msg_headers) || sizeof($a_msg_headers) != $max)
+    $revalidate = false;
+    if ($mbox_count)
       {
-      $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, "1:$max");
-      $a_msg_headers = array();
-      foreach ($a_header_index as $i => $headers)
-        $a_msg_headers[$headers->uid] = $headers;
-        
-// print "/**** fetch headers ****/\n";
+      // get cached headers
+      $a_out = $this->get_cache($mailbox.'.msg');
+      $a_out = is_array($a_out) ? $a_out : array(); // make sure we get an array
+
+      $cached_count = count($a_out);
+      $a_new = array();
+      $revalidate = true; // revalidate by default
+     
+      // if the cache count is greater then there have been changes for sure
+      if ($cached_count <= $mbox_count)
+        {
+        $from = $cached_count?$cached_count:1;
+       
+        //get new headers (at least one is returned)
+        $a_temp = iil_C_FetchHeaders($this->conn, $mailbox, $from . ':' . $mbox_count);
+        $duplicated = $cached_count?true:false;
+       
+        foreach ($a_temp as $hdr)
+          {
+          //skip the first one if duplicated
+          if ($duplicated)
+            {
+            //check for changes using the UID
+            $lastCacheHdr = end($a_out);
+            if ($hdr->uid === $lastCacheHdr->uid)
+              $revalidate = false;
+
+            $duplicated = false;
+            continue;
+            }
+           
+          //skip deleted ones
+          if (! $hdr->deleted)
+            $a_new[ $hdr->uid ] = $hdr;
+          }
+        }
+
+      //revalidate cache if needed
+      $to = $mbox_count - count($a_new);
+      if ($revalidate && $to !== 0)    //we'll need to reindex the array so we have to make a copy
+        {
+        $a_dirty = $a_out;
+        $a_out = array();
+        $a_buffers = array();
+
+        //fetch chunks of 20 headers
+        $step = 20;
+        $found = false;
+         
+        //fetch headers in blocks starting from new to old
+        do {
+          $from = $to-$step;
+          if ($from < 1) $from = 1;
+
+          //store the block in a temporal buffer
+          $a_buffers[$from] = iil_C_FetchHeaders($this->conn, $mailbox, $from . ':' . $to);
+
+          //compare the fetched headers with the ones in the cache
+          $idx = 0;
+          foreach ($a_buffers[$from] as $k=>$hdr)
+            {
+            //if it's different the comparison ends
+            if (!isset($a_dirty[$hdr->uid]) || $a_dirty[$hdr->uid]->id !== $hdr->id)
+              break;
+
+            //if we arrive here then we know that the older messages in cache are ok
+            $found = $hdr->id;
+            $idx++;
+            }
+
+          //remove from the buffer the headers which are already cached
+          if ($found)
+            $a_buffers[$from] = array_splice($a_buffers[$from], 0, $idx );
+             
+          $to = $from-1;
+          }
+        while ($found===false && $from > 1);
+
+        //just keep the headers we are certain that didn't change in the cache
+        if ($found !== false)
+          {
+          foreach ($a_dirty as $hdr)
+            {
+            if ($hdr->id > $found) break;
+            $a_out[$hdr->uid] = $hdr;
+            }
+          }
+           
+        //we builded the block buffers from new to older, we process them in reverse order
+        ksort($a_buffers, SORT_NUMERIC);
+        foreach ($a_buffers as $a_buff)
+          {
+          foreach ($a_buff as $hdr)
+            {
+            if (! $hdr->deleted)
+              $a_out[$hdr->uid] = $hdr;
+            }
+          }
+        }
+         
+      //array_merge() would reindex the keys, so we use this 'hack'
+      $a_out += $a_new;
       }
-    else
-      $headers_cached = TRUE;
+ 
+    //write headers list to cache if needed
+    if ($revalidate || count($a_out)!=$cached_count) {
+      $this->update_cache($mailbox.'.msg', $a_out);
+     }
 
-    // sort headers by a specific col
-    $a_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order);
-    
-    // write headers list to cache
-    if (!$headers_cached)
-      $this->update_cache($mailbox.'.msg', $a_msg_headers);
-
-    if (is_array($a_headers))
-      foreach ($a_headers as $header)
-        if (!$header->deleted)
-          $a_out[] = $header;
-
+    //sort headers by a specific col
+    $a_out = iil_SortHeaders( $a_out, $sort_field, $sort_order );
+   
     // return complete list of messages
     if (strtolower($page)=='all')
       return $a_out;
@@ -307,6 +432,57 @@
     return array_slice($a_out, $start_msg, $this->page_size);
     }
 
+
+  // old function; replaced 2005/10/18
+  // private method for listing message header
+  function _list_headers($mailbox='', $page=NULL, $sort_field='date', $sort_order='DESC')
+    {
+    $max = $this->_messagecount($mailbox);
+
+    if (!strlen($mailbox))
+      return array();
+
+    // get cached headers
+    $a_msg_headers = $this->get_cache($mailbox.'.msg');
+
+    // retrieve headers from IMAP
+    if (!is_array($a_msg_headers) || sizeof($a_msg_headers) != $max)
+      {
+      $a_header_index = iil_C_FetchHeaders($this->conn, $mailbox, "1:$max");
+      $a_msg_headers = array();
+
+      if (!empty($a_header_index))
+        foreach ($a_header_index as $i => $headers)
+          if (!$headers->deleted)
+            $a_msg_headers[$headers->uid] = $headers;
+      }
+    else
+      $headers_cached = TRUE;
+
+	if (!is_array($a_msg_headers))
+		return array();
+		
+    // sort headers by a specific col
+    $a_headers = iil_SortHeaders($a_msg_headers, $sort_field, $sort_order);
+
+	// free memory
+	unset($a_msg_headers);
+	
+    // write headers list to cache
+    if (!$headers_cached)
+      $this->update_cache($mailbox.'.msg', $a_headers);
+
+	if (empty($a_headers))
+		return array();
+		
+    // return complete list of messages
+    if (strtolower($page)=='all')
+      return $a_headers;
+	
+    $start_msg = ($this->list_page-1) * $this->page_size;
+    return array_slice($a_headers, $start_msg, $this->page_size);
+    }
+  
 
   // return sorted array of message UIDs
   function message_index($mbox='', $sort_field='date', $sort_order='DESC')
@@ -349,10 +525,10 @@
     // return cached header
     if ($a_msg_headers[$uid])
       return $a_msg_headers[$uid];
-    
+
     $msg_id = $this->_uid2id($uid);
     $header = iil_C_FetchHeader($this->conn, $mailbox, $msg_id);
-    
+
     // write headers cache
     $a_msg_headers[$uid] = $header;
     $this->update_cache($mailbox.'.msg', $a_msg_headers);
@@ -408,11 +584,13 @@
     else
       $result = iil_C_Flag($this->conn, $this->mailbox, join(',', $msg_ids), $flag);
 
-
     // reload message headers if cached
     $cache_key = $this->mailbox.'.msg';
-    if ($result && ($a_cached_headers = $this->get_cache($cache_key)))
+    if ($this->caching_enabled && $result && ($a_cached_headers = $this->get_cache($cache_key)))
       {
+      // close and re-open connection
+      $this->reconnect();
+
       foreach ($uids as $uid)
         {
         if (isset($a_cached_headers[$uid]))
@@ -473,12 +651,12 @@
     // exit if no message uids are specified
     if (!is_array($a_uids))
       return false;
-      
+
     // convert uids to message ids
     $a_mids = array();
     foreach ($a_uids as $uid)
       $a_mids[] = $this->_uid2id($uid, $from_mbox);
-        
+
     $moved = iil_C_Move($this->conn, join(',', $a_mids), $from_mbox, $to_mbox);
     
     // send expunge command in order to have the moved message
@@ -543,7 +721,19 @@
       }
 
     return $deleted;
+    }
 
+
+  // clear all messages in a specific mailbox
+  function clear_mailbox($mbox)
+    {
+    $mailbox = $mbox ? $this->_mod_mailbox($mbox) : $this->mailbox;
+    $msg_count = $this->_messagecount($mailbox, 'ALL');
+    
+    if ($msg_count>0)
+      return iil_C_ClearFolder($this->conn, $mailbox);
+    else
+      return 0;
     }
 
 
@@ -625,17 +815,21 @@
   function create_mailbox($name, $subscribe=FALSE)
     {
     $result = FALSE;
-    $abs_name = $this->_mod_mailbox($name);
+    $name_enc = UTF7EncodeString($name);
+    $abs_name = $this->_mod_mailbox($name_enc);
     $a_mailbox_cache = $this->get_cache('mailboxes');
+    
+    //if (strlen($this->root_ns))
+    //  $abs_name = $this->root_ns.$abs_name;
 
     if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache)))
       $result = iil_C_CreateFolder($this->conn, $abs_name);
 
     // update mailboxlist cache
     if ($result && $subscribe)
-      $this->subscribe($name);
+      $this->subscribe($name_enc);
 
-    return $result;
+    return $result ? $name : FALSE;
     }
 
 
@@ -681,14 +875,22 @@
 
 
   /* --------------------------------
-   *   internal cacheing functions
+   *   internal caching functions
    * --------------------------------*/
-   
+
+
+  function set_caching($set)
+    {
+    if ($set && function_exists('rcube_read_cache'))
+      $this->caching_enabled = TRUE;
+    else
+      $this->caching_enabled = FALSE;
+    }
 
   function get_cache($key)
     {
     // read cache
-    if (!isset($this->cache[$key]) && $this->cacheing_enabled)
+    if (!isset($this->cache[$key]) && $this->caching_enabled)
       {
       $cache_data = rcube_read_cache('IMAP.'.$key);
       $this->cache[$key] = strlen($cache_data) ? unserialize($cache_data) : FALSE;
@@ -708,7 +910,7 @@
 
   function write_cache()
     {
-    if ($this->cacheing_enabled && $this->cache_changed)
+    if ($this->caching_enabled && $this->cache_changed)
       {
       foreach ($this->cache as $key => $data)
         {
@@ -870,7 +1072,7 @@
   // convert body chars according to the ctype_parameters
   function charset_decode($body, $ctype_param)
     {
-    if (is_array($ctype_param) && strlen($ctype_param['charset']))
+    if (is_array($ctype_param) && !empty($ctype_param['charset']))
       return decode_specialchars($body, $ctype_param['charset']);
 
     return $body;
@@ -884,9 +1086,12 @@
 
   function _mod_mailbox($mbox, $mode='in')
     {
-    if ($this->root_dir && $mode=='in')
-      $mbox = $this->root_dir.'/'.$mbox;
-    else if ($this->root_dir && $mode=='out')
+    if ((!empty($this->root_ns) && $this->root_ns == $mbox) || ($mbox == 'INBOX' && $mode == 'in'))
+      return $mbox;
+
+    if (!empty($this->root_dir) && $mode=='in') 
+      $mbox = $this->root_dir.$this->delimiter.$mbox;
+    else if (strlen($this->root_dir) && $mode=='out') 
       $mbox = substr($mbox, strlen($this->root_dir)+1);
 
     return $mbox;

--
Gitblit v1.9.1