thomascube
2006-08-10 87e3ed6ed09a9fcd3cab45a6ce674396e51b95bb
program/include/rcube_imap.inc
@@ -26,7 +26,6 @@
 */
require_once('lib/imap.inc');
require_once('lib/mime.inc');
require_once('lib/utf7.inc');
/**
@@ -36,7 +35,7 @@
 *
 * @package    RoundCube Webmail
 * @author     Thomas Bruederli <roundcube@gmail.com>
 * @version    1.26
 * @version    1.31
 * @link       http://ilohamail.org
 */
class rcube_imap
@@ -52,7 +51,8 @@
  var $sort_order = 'DESC';
  var $delimiter = NULL;
  var $caching_enabled = FALSE;
  var $default_folders = array('inbox', 'drafts', 'sent', 'junk', 'trash');
  var $default_folders = array('INBOX');
  var $default_folders_lc = array('inbox');
  var $cache = array();
  var $cache_keys = array();  
  var $cache_changes = array();
@@ -208,15 +208,16 @@
    {
    if (is_array($arr))
      {
      $this->default_folders = array();
      // add mailbox names lower case
      foreach ($arr as $mbox_row)
        $this->default_folders[] = strtolower($mbox_row);
      $this->default_folders = $arr;
      $this->default_folders_lc = array();
      // add inbox if not included
      if (!in_array('inbox', $this->default_folders))
        array_unshift($arr, 'inbox');
      if (!in_array_nocase('INBOX', $this->default_folders))
        array_unshift($this->default_folders, 'INBOX');
      // create a second list with lower cased names
      foreach ($this->default_folders as $mbox)
        $this->default_folders_lc[] = strtolower($mbox);
      }
    }
@@ -333,6 +334,10 @@
        $a_out[] = $name;
      }
    // INBOX should always be available
    if (!in_array_nocase('INBOX', $a_out))
      array_unshift($a_out, 'INBOX');
    // sort mailboxes
    $a_out = $this->_sort_mailbox_list($a_out);
@@ -361,20 +366,6 @@
    
    if (!is_array($a_folders) || !sizeof($a_folders))
      $a_folders = array();
    // create Default folders if they do not exist
    global $CONFIG;
    foreach ($CONFIG['default_imap_folders'] as $folder)
      {
      if (!in_array_nocase($folder, $a_folders))
        {
        $this->create_mailbox($folder, TRUE);
        $this->subscribe($folder);
        }
      }
    $a_folders = iil_C_ListSubscribed($this->conn, $this->_mod_mailbox($root), $filter);
    $a_mailbox_cache = array();
    // write mailboxlist to cache
    $this->update_cache('mailboxes', $a_folders);
@@ -516,28 +507,33 @@
      $a_msg_headers = $this->get_message_cache($cache_key, $start_msg, $start_msg+$this->page_size, $this->sort_field, $this->sort_order);
      $headers_sorted = TRUE;
      }
    // cache is dirty, sync it
    else if ($this->caching_enabled && $cache_status==-1 && !$recursive)
      {
      $this->sync_header_index($mailbox);
      return $this->_list_headers($mailbox, $page, $this->sort_field, $this->sort_order, TRUE);
      }
    else
      {
      // retrieve headers from IMAP
      if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')))
        {
        {
        $msgs = $msg_index[$begin];
        for ($i=$begin+1; $i < $end; $i++)
          $msgs = $msgs.','.$msg_index[$i];
        }
      else
        {
        $msgs = sprintf("%d:%d", $begin+1, $end);
        $msgs = sprintf("%d:%d", $begin+1, $end);
        $i = 0;
        for ($msg_seqnum = $begin; $msg_seqnum <= $end; $msg_seqnum++)
          $msg_index[$i++] = $msg_seqnum;
        }
      // cache is dirty, sync it
      if ($this->caching_enabled && $cache_status==-1 && !$recursive)
        {
        $this->sync_header_index($mailbox);
        return $this->_list_headers($mailbox, $page, $this->sort_field, $this->sort_order, TRUE);
        }
      // use this class for message sorting
      $sorter = new rcube_header_sorter();
      $sorter->set_sequence_numbers($msg_index);
      // fetch reuested headers from server
      $a_msg_headers = array();
@@ -560,16 +556,17 @@
    // if not already sorted
    if (!$headers_sorted)
      $a_msg_headers = iil_SortHeaders($a_msg_headers, $this->sort_field, $this->sort_order);
      {
      $sorter->sort_headers($a_msg_headers);
    if (!$headers_sorted && $this->sort_order == 'DESC')
      $a_msg_headers = array_reverse($a_msg_headers);
      if ($this->sort_order == 'DESC')
        $a_msg_headers = array_reverse($a_msg_headers);
      }
    return array_values($a_msg_headers);
    }
  /**
   * Public method for listing a specific set of headers
@@ -829,13 +826,19 @@
   * @return array   search results as list of message ids
   * @access public
   */
  function search($mbox_name='', $criteria='ALL', $str=NULL)
  function search($mbox_name='', $criteria='ALL', $str=NULL, $charset=NULL)
    {
    $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
    if ($str && $criteria)
      {
      $criteria = 'CHARSET UTF-8 '.$criteria.' "'.UTF7EncodeString($str).'"';
      return $this->_search_index($mailbox, $criteria);
      $search = (!empty($charset) ? "CHARSET $charset " : '') . sprintf("%s {%d}\r\n%s", $criteria, strlen($str), $str);
      $results = $this->_search_index($mailbox, $search);
      // 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');
      return $results;
      }
    else
      return $this->_search_index($mailbox, $criteria);
@@ -1149,7 +1152,12 @@
   * --------------------------------*/
  // return an array with all folders available in IMAP server
  /**
   * Get a list of all folders available on the IMAP server
   *
   * @param string IMAP root dir
   * @return array Inbdexed array with folder names
   */
  function list_unsubscribed($root='')
    {
    static $sa_unsubscribed;
@@ -1191,7 +1199,9 @@
    }
  // subscribe to a specific mailbox(es)
  /**
   * subscribe to a specific mailbox(es)
   */
  function subscribe($mbox_name, $mode='subscribe')
    {
    if (is_array($mbox_name))
@@ -1204,7 +1214,9 @@
    }
  // unsubscribe mailboxes
  /**
   * unsubscribe mailboxes
   */
  function unsubscribe($mbox_name)
    {
    if (is_array($mbox_name))
@@ -1217,7 +1229,13 @@
    }
  // create a new mailbox on the server and register it in local cache
  /**
   * Create a new mailbox on the server and register it in local cache
   *
   * @param string  New mailbox name (as utf-7 string)
   * @param boolean True if the new mailbox should be subscribed
   * @param string  Name of the created mailbox, false on error
   */
  function create_mailbox($name, $subscribe=FALSE)
    {
    $result = FALSE;
@@ -1225,54 +1243,64 @@
    // replace backslashes
    $name = preg_replace('/[\\\]+/', '-', $name);
    $name_enc = UTF7EncodeString($name);
    // reduce mailbox name to 100 chars
    $name_enc = substr($name_enc, 0, 100);
    $name = substr($name, 0, 100);
    $abs_name = $this->_mod_mailbox($name_enc);
    $abs_name = $this->_mod_mailbox($name);
    $a_mailbox_cache = $this->get_cache('mailboxes');
    if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache)))
    if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array_nocase($abs_name, $a_mailbox_cache)))
      $result = iil_C_CreateFolder($this->conn, $abs_name);
    // update mailboxlist cache
    if ($result && $subscribe)
      $this->subscribe($name_enc);
    // try to subscribe it
    if ($subscribe)
      $this->subscribe($name);
    return $result ? $name : FALSE;
    }
  // set a new name to an existing mailbox
  function rename_mailbox($mbox_name, $new_name, $subscribe=TRUE)
  /**
   * Set a new name to an existing mailbox
   *
   * @param string Mailbox to rename (as utf-7 string)
   * @param string New mailbox name (as utf-7 string)
   * @param string Name of the renames mailbox, false on error
   */
  function rename_mailbox($mbox_name, $new_name)
    {
    $result = FALSE;
    // replace backslashes
    $name = preg_replace('/[\\\]+/', '-', $new_name);
    // encode mailbox name and reduce it to 100 chars
    $name = substr($new_name, 0, 100);
    $name_enc = UTF7EncodeString($new_name);
    // make absolute path
    $mailbox = $this->_mod_mailbox($mbox_name);
    $abs_name = $this->_mod_mailbox($name);
    // reduce mailbox name to 100 chars
    $name_enc = substr($name_enc, 0, 100);
    if (strlen($abs_name))
      $result = iil_C_RenameFolder($this->conn, $mailbox, $abs_name);
    $abs_name = $this->_mod_mailbox($name_enc);
    $a_mailbox_cache = $this->get_cache('mailboxes');
    if (strlen($abs_name) && (!is_array($a_mailbox_cache) || !in_array($abs_name, $a_mailbox_cache)))
      $result = iil_C_RenameFolder($this->conn, $mbox_name, $abs_name);
    // update mailboxlist cache
    if ($result && $subscribe)
      $this->unsubscribe($mbox_name);
      $this->subscribe($name_enc);
    // clear cache
    if ($result)
      {
      $this->clear_message_cache($mailbox.'.msg');
      $this->clear_cache('mailboxes');
      }
    // try to subscribe it
    $this->subscribe($name);
    return $result ? $name : FALSE;
    }
  // remove mailboxes from server
  /**
   * remove mailboxes from server
   */
  function delete_mailbox($mbox_name)
    {
    $deleted = FALSE;
@@ -1289,7 +1317,7 @@
        // unsubscribe mailbox before deleting
        iil_C_UnSubscribe($this->conn, $mailbox);
        // send delete command to server
        $result = iil_C_DeleteFolder($this->conn, $mailbox);
        if ($result>=0)
@@ -1306,6 +1334,28 @@
    return $deleted;
    }
  /**
   * Create all folders specified as default
   */
  function create_default_folders()
    {
    $a_folders = iil_C_ListMailboxes($this->conn, $this->_mod_mailbox(''), '*');
    $a_subscribed = iil_C_ListSubscribed($this->conn, $this->_mod_mailbox(''), '*');
    // create default folders if they do not exist
    foreach ($this->default_folders as $folder)
      {
      $abs_name = $this->_mod_mailbox($folder);
      if (!in_array_nocase($abs_name, $a_subscribed))
        {
        if (!in_array_nocase($abs_name, $a_folders))
          $this->create_mailbox($folder, TRUE);
        else
          $this->subscribe($folder);
        }
      }
    }
@@ -1662,7 +1712,7 @@
    {
    $a = $this->_parse_address_list($input);
    $out = array();
    if (!is_array($a))
      return $out;
@@ -1823,7 +1873,7 @@
  function _mod_mailbox($mbox_name, $mode='in')
    {
    if ((!empty($this->root_ns) && $this->root_ns == $mbox_name) || ($mbox_name == 'INBOX' && $mode == 'in'))
    if ((!empty($this->root_ns) && $this->root_ns == $mbox_name) || $mbox_name == 'INBOX')
      return $mbox_name;
    if (!empty($this->root_dir) && $mode=='in') 
@@ -1845,8 +1895,8 @@
      {
      if ($folder{0}=='.')
         continue;
      if (($p = array_search(strtolower($folder), $this->default_folders))!==FALSE)
      if (($p = array_search(strtolower($folder), $this->default_folders_lc))!==FALSE)
         $a_defaults[$p] = $folder;
      else
        $a_out[] = $folder;
@@ -2002,12 +2052,13 @@
    {
    $a = $this->_explode_quoted_string(',', $str);
    $result = array();
    foreach ($a as $key => $val)
      {
      $val = str_replace("\"<", "\" <", $val);
      $sub_a = $this->_explode_quoted_string(' ', $val);
      $sub_a = $this->_explode_quoted_string(' ', $this->decode_header($val));
      $result[$key]['name'] = '';
      foreach ($sub_a as $k => $v)
        {
        if ((strpos($v, '@') > 0) && (strpos($v, '.') > 0)) 
@@ -2017,9 +2068,7 @@
        }
        
      if (empty($result[$key]['name']))
        $result[$key]['name'] = $result[$key]['address'];
      $result[$key]['name'] = $this->decode_header($result[$key]['name']);
        $result[$key]['name'] = $result[$key]['address'];
      }
    
    return $result;
@@ -2045,9 +2094,89 @@
/**
 * rcube_header_sorter
 *
 * Class for sorting an array of iilBasicHeader objects in a predetermined order.
 *
 * @author Eric Stadtherr
 */
class rcube_header_sorter
{
   var $sequence_numbers = array();
   /**
    * set the predetermined sort order.
    *
    * @param array $seqnums numerically indexed array of IMAP message sequence numbers
    */
   function set_sequence_numbers($seqnums)
   {
      $this->sequence_numbers = $seqnums;
   }
   /**
    * sort the array of header objects
    *
    * @param array $headers array of iilBasicHeader objects indexed by UID
    */
   function sort_headers(&$headers)
   {
      /*
       * uksort would work if the keys were the sequence number, but unfortunately
       * the keys are the UIDs.  We'll use uasort instead and dereference the value
       * to get the sequence number (in the "id" field).
       *
       * uksort($headers, array($this, "compare_seqnums"));
       */
       uasort($headers, array($this, "compare_seqnums"));
   }
   /**
    * get the position of a message sequence number in my sequence_numbers array
    *
    * @param integer $seqnum message sequence number contained in sequence_numbers
    */
   function position_of($seqnum)
   {
      $c = count($this->sequence_numbers);
      for ($pos = 0; $pos <= $c; $pos++)
      {
         if ($this->sequence_numbers[$pos] == $seqnum)
            return $pos;
      }
      return -1;
   }
   /**
    * Sort method called by uasort()
    */
   function compare_seqnums($a, $b)
   {
      // First get the sequence number from the header object (the 'id' field).
      $seqa = $a->id;
      $seqb = $b->id;
      // then find each sequence number in my ordered list
      $posa = $this->position_of($seqa);
      $posb = $this->position_of($seqb);
      // return the relative position as the comparison value
      $ret = $posa - $posb;
      return $ret;
   }
}
function quoted_printable_encode($input="", $line_max=76, $space_conv=false)
/**
 * Add quoted-printable encoding to a given string
 *
 * @param string  $input      string to encode
 * @param int     $line_max   add new line after this number of characters
 * @param boolena $space_conf true if spaces should be converted into =20
 * @return encoded string
 */
function quoted_printable_encode($input, $line_max=76, $space_conv=false)
  {
  $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
  $lines = preg_split("/(?:\r\n|\r|\n)/", $input);