thomascube
2008-03-21 17b5fb797f4bc142fee8cd72ade3890b4dfdbd82
program/include/rcube_imap.inc
@@ -5,7 +5,7 @@
 | program/include/rcube_imap.inc                                        |
 |                                                                       |
 | This file is part of the RoundCube Webmail client                     |
 | Copyright (C) 2005-2006, RoundCube Dev. - Switzerland                 |
 | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
 | Licensed under the GNU GPL                                            |
 |                                                                       |
 | PURPOSE:                                                              |
@@ -35,7 +35,7 @@
 *
 * @package    Mail
 * @author     Thomas Bruederli <roundcube@gmail.com>
 * @version    1.36
 * @version    1.40
 * @link       http://ilohamail.org
 */
class rcube_imap
@@ -51,6 +51,7 @@
  var $sort_order = 'DESC';
  var $delimiter = NULL;
  var $caching_enabled = FALSE;
  var $default_charset = 'ISO-8859-1';
  var $default_folders = array('INBOX');
  var $default_folders_lc = array('inbox');
  var $cache = array();
@@ -65,6 +66,7 @@
  var $search_string = '';
  var $search_charset = '';
  var $debug_level = 1;
  var $error_code = 0;
  /**
@@ -96,17 +98,17 @@
   * @param  string   Username for IMAP account
   * @param  string   Password for IMAP account
   * @param  number   Port to connect to
   * @param  boolean  Use SSL connection
   * @param  string   SSL schema (either ssl or tls) or null if plain connection
   * @return boolean  TRUE on success, FALSE on failure
   * @access public
   */
  function connect($host, $user, $pass, $port=143, $use_ssl=FALSE)
  function connect($host, $user, $pass, $port=143, $use_ssl=null)
    {
    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()))
      $ICL_SSL = TRUE;
      $ICL_SSL = $use_ssl == 'imaps' ? 'ssl' : $use_ssl;
    else if ($use_ssl)
      {
      raise_error(array('code' => 403, 'type' => 'imap', 'file' => __FILE__,
@@ -131,6 +133,7 @@
    // write error log
    else if (!$this->conn && $GLOBALS['iil_error'])
      {
      $this->error_code = $GLOBALS['iil_errornum'];
      raise_error(array('code' => 403,
                       'type' => 'imap',
                       'message' => $GLOBALS['iil_error']), TRUE, FALSE);
@@ -198,6 +201,20 @@
    
    if (empty($this->delimiter))
      $this->get_hierarchy_delimiter();
    }
  /**
   * Set default message charset
   *
   * This will be used for message decoding if a charset specification is not available
   *
   * @param  string   Charset string
   * @access public
   */
  function set_charset($cs)
    {
    $this->default_charset = $ch;
    }
@@ -287,7 +304,7 @@
      
    $this->search_subject = $subject;
    $this->search_string = $str;
    $this->search_set = is_array($msgs) ? $msgs : NULL;
    $this->search_set = (array)$msgs;
    $this->search_charset = $charset;
    }
@@ -439,8 +456,8 @@
      $mailbox = $this->mailbox;
      
    // count search set
    if ($this->search_set && $mailbox == $this->mailbox && $mode == 'ALL')
      return count($this->search_set);
    if ($this->search_string && $mailbox == $this->mailbox && $mode == 'ALL' && !$force)
      return count((array)$this->search_set);
    $a_mailbox_cache = $this->get_cache('messagecount');
    
@@ -522,13 +539,10 @@
      return array();
    // use saved message set
    if ($this->search_set && $mailbox == $this->mailbox)
    if ($this->search_string && $mailbox == $this->mailbox)
      return $this->_list_header_set($mailbox, $this->search_set, $page, $sort_field, $sort_order);
    if ($sort_field!=NULL)
      $this->sort_field = $sort_field;
    if ($sort_order!=NULL)
      $this->sort_order = strtoupper($sort_order);
    $this->_set_sort_order($sort_field, $sort_order);
    $max = $this->_messagecount($mailbox);
    $start_msg = ($this->list_page-1) * $this->page_size;
@@ -645,10 +659,7 @@
    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);
    $this->_set_sort_order($sort_field, $sort_order);
    $max = count($msgs);
    $start_msg = ($this->list_page-1) * $this->page_size;
@@ -762,13 +773,20 @@
   */
  function message_index($mbox_name='', $sort_field=NULL, $sort_order=NULL)
    {
    if ($sort_field!=NULL)
      $this->sort_field = $sort_field;
    if ($sort_order!=NULL)
      $this->sort_order = strtoupper($sort_order);
    $this->_set_sort_order($sort_field, $sort_order);
    $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox;
    $key = "$mbox:".$this->sort_field.":".$this->sort_order.".msgi";
    $key = "{$mailbox}:{$this->sort_field}:{$this->sort_order}:{$this->search_string}.msgi";
    // we have a saved search result. get index from there
    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);
      foreach (iil_SortHeaders($a_msg_headers, $this->sort_field, $this->sort_order) as $i => $msg)
        $this->cache[$key][] = $msg->uid;
    }
    // have stored it in RAM
    if (isset($this->cache[$key]))
@@ -941,6 +959,20 @@
      
    return $this->get_search_set();
    }
  /**
   * Check if the given message ID is part of the current search set
   *
   * @return boolean True on match or if no search request is stored
   */
  function in_searchset($msgid)
  {
    if (!empty($this->search_string))
      return in_array("$msgid", (array)$this->search_set, true);
    else
      return true;
  }
  /**
@@ -965,8 +997,8 @@
    // write headers cache
    if ($headers)
      {
      if ($is_uid)
        $this->uid_id_map[$mbox_name][$uid] = $headers->id;
      if ($headers->uid && $headers->id)
        $this->uid_id_map[$mailbox][$headers->uid] = $headers->id;
      $this->add_message_cache($mailbox.'.msg', $headers->id, $headers);
      }
@@ -1003,7 +1035,7 @@
    if (!empty($structure))
      {
      $this->_msg_id = $msg_id;
      $headers = $this->get_headers($msg_id, NULL, FALSE);
      $headers = $this->get_headers($uid);
      
      $struct = &$this->_structure_part($structure);
      $struct->headers = get_object_vars($headers);
@@ -1128,12 +1160,16 @@
      }
      
    // normalize filename property
    if (!empty($struct->d_parameters['filename']))
      $struct->filename = $this->decode_mime_string($struct->d_parameters['filename']);
    else if (!empty($struct->ctype_parameters['name']))
      $struct->filename = $this->decode_mime_string($struct->ctype_parameters['name']);
    if ($filename_mime = $struct->d_parameters['filename'] ? $struct->d_parameters['filename'] : $struct->ctype_parameters['name'])
      $struct->filename = rcube_imap::decode_mime_string($filename_mime, $this->default_charset);
    else if ($filename_encoded = $struct->d_parameters['filename*'] ? $struct->d_parameters['filename*'] : $struct->ctype_parameters['name*'])
    {
      // decode filename according to RFC 2231, Section 4
      list($filename_charset,, $filename_urlencoded) = split('\'', $filename_encoded);
      $struct->filename = rcube_charset_convert(urldecode($filename_urlencoded), $filename_charset);
    }
    else if (!empty($struct->headers['content-description']))
      $struct->filename = $this->decode_mime_string($struct->headers['content-description']);
      $struct->filename = rcube_imap::decode_mime_string($struct->headers['content-description'], $this->default_charset);
      
    return $struct;
    }
@@ -1199,23 +1235,30 @@
    if ($print)
      {
      iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, ($o_part->encoding=='base64'?3:2));
      $body = TRUE;
      $mode = $o_part->encoding == 'base64' ? 3 : ($o_part->encoding == 'quoted-printable' ? 1 : 2);
      $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, $mode);
      // we have to decode the part manually before printing
      if ($mode == 1)
        {
        echo $this->mime_decode($body, $o_part->encoding);
        $body = true;
        }
      }
    else
      {
      $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 1);
      // decode part body
      if ($o_part->encoding=='base64' || $o_part->encoding=='quoted-printable')
      if ($o_part->encoding)
        $body = $this->mime_decode($body, $o_part->encoding);
      // convert charset (if text or message part)
      if ($o_part->ctype_primary=='text' || $o_part->ctype_primary=='message')
        {
        // assume ISO-8859-1 if no charset specified
        // assume default if no charset specified
        if (empty($o_part->charset))
          $o_part->charset = 'ISO-8859-1';
          $o_part->charset = $this->default_charset;
        $body = rcube_charset_convert($body, $o_part->charset);
        }
@@ -1276,7 +1319,7 @@
   * Set message flag to one or several messages
   *
   * @param mixed  Message UIDs as array or as comma-separated string
   * @param string Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT
   * @param string Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT, MDNSENT
   * @return boolean True on success, False on failure
   */
  function set_flag($uids, $flag)
@@ -1544,7 +1587,7 @@
    if ($result>=0 && $clear_cache)
      {
      //$this->clear_message_cache($mailbox.'.msg');
      $this->clear_message_cache($mailbox.'.msg');
      $this->_clear_messagecount($mailbox);
      }
      
@@ -1701,9 +1744,19 @@
    if (strlen($abs_name))
      $result = iil_C_RenameFolder($this->conn, $mailbox, $abs_name);
    // clear cache
    if ($result)
      {
      $delm = $this->get_hierarchy_delimiter();
      // check if mailbox children are subscribed
      foreach ($a_subscribed as $c_subscribed)
        if (preg_match('/^'.preg_quote($mailbox.$delm, '/').'/', $c_subscribed))
          {
          iil_C_UnSubscribe($this->conn, $c_subscribed);
          iil_C_Subscribe($this->conn, preg_replace('/^'.preg_quote($mailbox, '/').'/', $abs_name, $c_subscribed));
          }
      // clear cache
      $this->clear_message_cache($mailbox.'.msg');
      $this->clear_cache('mailboxes');      
      }
@@ -1731,6 +1784,8 @@
    else if (is_string($mbox_name) && strlen($mbox_name))
      $a_mboxes = explode(',', $mbox_name);
    $all_mboxes = iil_C_ListMailboxes($this->conn, $this->_mod_mailbox($root), '*');
    if (is_array($a_mboxes))
      foreach ($a_mboxes as $mbox_name)
        {
@@ -1743,6 +1798,19 @@
        $result = iil_C_DeleteFolder($this->conn, $mailbox);
        if ($result>=0)
          $deleted = TRUE;
        foreach ($all_mboxes as $c_mbox)
          {
          $regex = preg_quote($mailbox . $this->delimiter, '/');
          $regex = '/^' . $regex . '/';
          if (preg_match($regex, $c_mbox))
            {
            iil_C_UnSubscribe($this->conn, $c_mbox);
            $result = iil_C_DeleteFolder($this->conn, $c_mbox);
            if ($result>=0)
              $deleted = TRUE;
            }
          }
        }
    // clear mailboxlist cache
@@ -2021,6 +2089,10 @@
        {
        $uid = $sql_arr['uid'];
        $this->cache[$cache_key][$uid] = unserialize($sql_arr['headers']);
        // featch headers if unserialize failed
        if (empty($this->cache[$cache_key][$uid]))
          $this->cache[$cache_key][$uid] = iil_C_FetchHeader($this->conn, preg_replace('/.msg$/', '', $key), $uid, true);
        }
      }
      
@@ -2032,10 +2104,8 @@
   */
  function &get_cached_message($key, $uid, $struct=false)
    {
    if (!$this->caching_enabled)
      return FALSE;
    $internal_key = '__single_msg';
    if ($this->caching_enabled && (!isset($this->cache[$internal_key][$uid]) ||
        ($struct && empty($this->cache[$internal_key][$uid]->structure))))
      {
@@ -2096,9 +2166,17 @@
   */
  function add_message_cache($key, $index, $headers, $struct=null)
    {
    if (!$this->caching_enabled || empty($key) || !is_object($headers) || empty($headers->uid))
    if (empty($key) || !is_object($headers) || empty($headers->uid))
        return;
    // add to internal (fast) cache
    $this->cache['__single_msg'][$headers->uid] = $headers;
    $this->cache['__single_msg'][$headers->uid]->structure = $struct;
    // no further caching
    if (!$this->caching_enabled)
      return;
    // check for an existing record (probly headers are cached but structure not)
    $sql_result = $this->db->query(
        "SELECT message_id
@@ -2234,7 +2312,7 @@
   */
  function decode_header($input, $remove_quotes=FALSE)
    {
    $str = $this->decode_mime_string((string)$input);
    $str = rcube_imap::decode_mime_string((string)$input, $this->default_charset);
    if ($str{0}=='"' && $remove_quotes)
      $str = str_replace('"', '', $str);
    
@@ -2351,7 +2429,7 @@
      return rcube_charset_convert($body, $ctype_param['charset']);
    // defaults to what is specified in the class header
    return rcube_charset_convert($body,  'ISO-8859-1');
    return rcube_charset_convert($body,  $this->default_charset);
    }
@@ -2405,6 +2483,17 @@
    return $mbox_name;
    }
  /**
   * Validate the given input and save to local properties
   * @access private
   */
  function _set_sort_order($sort_field, $sort_order)
  {
    if ($sort_field != null)
      $this->sort_field = asciiwords($sort_field);
    if ($sort_order != null)
      $this->sort_order = strtoupper($sort_order) == 'DESC' ? 'DESC' : 'ASC';
  }
  /**
   * Sort mailboxes first by default folders and then in alphabethical order
@@ -2420,7 +2509,7 @@
      if ($folder{0}=='.')
        continue;
      if (($p = array_search(strtolower($folder), $this->default_folders_lc))!==FALSE)
      if (($p = array_search(strtolower($folder), $this->default_folders_lc)) !== false && !$a_defaults[$p])
        $a_defaults[$p] = $folder;
      else
        $a_out[] = $folder;
@@ -2454,7 +2543,16 @@
    if (!$mbox_name)
      $mbox_name = $this->mailbox;
      
    return iil_C_ID2UID($this->conn, $mbox_name, $id);
    $index = array_flip((array)$this->uid_id_map[$mbox_name]);
    if (isset($index[$id]))
      $uid = $index[$id];
    else
      {
      $uid = iil_C_ID2UID($this->conn, $mbox_name, $id);
      $this->uid_id_map[$mbox_name][$uid] = $id;
      }
    return $uid;
    }