thomascube
2011-08-19 d43d4bcf44a1feae4274e51f41ce9625147f9f85
program/include/rcube_imap.php
@@ -80,19 +80,18 @@
    private $db_header_fields = array('idx', 'uid', 'subject', 'from', 'to', 'cc', 'date', 'size');
    private $options = array('auth_method' => 'check');
    private $host, $user, $pass, $port, $ssl;
    private $caching = false;
    /**
     * All (additional) headers used (in any way) by Roundcube
     * Not listed here: DATE, FROM, TO, SUBJECT, CONTENT-TYPE, LIST-POST
     * Not listed here: DATE, FROM, TO, CC, REPLY-TO, SUBJECT, CONTENT-TYPE, LIST-POST
     * (used for messages listing) are hardcoded in rcube_imap_generic::fetchHeaders()
     *
     * @var array
     * @see rcube_imap::fetch_add_headers
     */
    private $all_headers = array(
        'REPLY-TO',
        'IN-REPLY-TO',
        'CC',
        'BCC',
        'MESSAGE-ID',
        'CONTENT-TRANSFER-ENCODING',
@@ -121,6 +120,13 @@
    function __construct()
    {
        $this->conn = new rcube_imap_generic();
        // Set namespace and delimiter from session,
        // so some methods would work before connection
        if (isset($_SESSION['imap_namespace']))
            $this->namespace = $_SESSION['imap_namespace'];
        if (isset($_SESSION['imap_delimiter']))
            $this->delimiter = $_SESSION['imap_delimiter'];
    }
@@ -549,12 +555,6 @@
    private function set_env()
    {
        if ($this->delimiter !== null && $this->namespace !== null) {
            return;
        }
        if (isset($_SESSION['imap_namespace']) && isset($_SESSION['imap_delimiter'])) {
            $this->namespace = $_SESSION['imap_namespace'];
            $this->delimiter = $_SESSION['imap_delimiter'];
            return;
        }
@@ -2163,7 +2163,7 @@
                    if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
                        $mime_part_headers[] = $tmp_part_id;
                    }
                    else if (in_array('name', (array)$part[$i][2]) && (empty($part[$i][3]) || $part[$i][3]=='NIL')) {
                    else if (in_array('name', (array)$part[$i][2]) && empty($part[$i][3])) {
                        $mime_part_headers[] = $tmp_part_id;
                    }
                }
@@ -2231,13 +2231,13 @@
        }
        // read content encoding
        if (!empty($part[5]) && $part[5]!='NIL') {
        if (!empty($part[5])) {
            $struct->encoding = strtolower($part[5]);
            $struct->headers['content-transfer-encoding'] = $struct->encoding;
        }
        // get part size
        if (!empty($part[6]) && $part[6]!='NIL')
        if (!empty($part[6]))
            $struct->size = intval($part[6]);
        // read part disposition
@@ -2264,7 +2264,7 @@
        }
        // get part ID
        if (!empty($part[3]) && $part[3]!='NIL') {
        if (!empty($part[3])) {
            $struct->content_id = $part[3];
            $struct->headers['content-id'] = $part[3];
@@ -3083,20 +3083,36 @@
                $a_folders = $this->conn->listMailboxes($root, $name,
                    NULL, array('SUBSCRIBED'));
                // remove non-existent folders
                if (is_array($a_folders)) {
                // unsubscribe non-existent folders, remove from the list
                if (is_array($a_folders) && $name == '*') {
                    foreach ($a_folders as $idx => $folder) {
                        if ($this->conn->data['LIST'] && ($opts = $this->conn->data['LIST'][$folder])
                            && in_array('\\NonExistent', $opts)
                        ) {
                            $this->conn->unsubscribe($folder);
                            unset($a_folders[$idx]);
                        }
                        }
                    }
                }
            }
            // retrieve list of folders from IMAP server using LSUB
            else {
                $a_folders = $this->conn->listSubscribed($root, $name);
                // unsubscribe non-existent folders, remove from the list
                if (is_array($a_folders) && $name == '*') {
                    foreach ($a_folders as $idx => $folder) {
                        if ($this->conn->data['LIST'] && ($opts = $this->conn->data['LIST'][$folder])
                            && in_array('\\Noselect', $opts)
                        ) {
                            // Some servers returns \Noselect for existing folders
                            if (!$this->mailbox_exists($folder)) {
                                $this->conn->unsubscribe($folder);
                                unset($a_folders[$idx]);
                            }
                        }
                    }
                }
            }
        }
@@ -3232,7 +3248,7 @@
        // try to subscribe it
        if ($result) {
            // clear cache
            $this->clear_cache('/^mailboxes.*/', true);
            $this->clear_cache('mailboxes', true);
            if ($subscribe)
                $this->subscribe($mailbox);
@@ -3288,7 +3304,7 @@
            // clear cache
            $this->clear_message_cache($mailbox.'.msg');
            $this->clear_cache('/^mailboxes.*/', true);
            $this->clear_cache('mailboxes', true);
        }
        return $result;
@@ -3330,7 +3346,7 @@
            // clear mailbox-related cache
            $this->clear_message_cache($mailbox.'.msg');
            $this->clear_cache('/^mailboxes.*/', true);
            $this->clear_cache('mailboxes', true);
        }
        return $result;
@@ -3485,6 +3501,86 @@
        $opts = $this->conn->data['LIST'][$mailbox];
        return is_array($opts) ? $opts : array();
    }
    /**
     * Returns extended information about the folder
     *
     * @param string $mailbox Folder name
     *
     * @return array Data
     */
    function mailbox_info($mailbox)
    {
        if ($this->icache['options'] && $this->icache['options']['name'] == $mailbox) {
            return $this->icache['options'];
        }
        $acl       = $this->get_capability('ACL');
        $namespace = $this->get_namespace();
        $options   = array();
        // check if the folder is a namespace prefix
        if (!empty($namespace)) {
            $mbox = $mailbox . $this->delimiter;
            foreach ($namespace as $ns) {
                if (!empty($ns)) {
                    foreach ($ns as $item) {
                        if ($item[0] === $mbox) {
                            $options['is_root'] = true;
                            break 2;
                        }
                    }
                }
            }
        }
        // check if the folder is other user virtual-root
        if (!$options['is_root'] && !empty($namespace) && !empty($namespace['other'])) {
            $parts = explode($this->delimiter, $mailbox);
            if (count($parts) == 2) {
                $mbox = $parts[0] . $this->delimiter;
                foreach ($namespace['other'] as $item) {
                    if ($item[0] === $mbox) {
                        $options['is_root'] = true;
                        break;
                    }
                }
            }
        }
        $options['name']      = $mailbox;
        $options['options']   = $this->mailbox_options($mailbox, true);
        $options['namespace'] = $this->mailbox_namespace($mailbox);
        $options['rights']    = $acl && !$options['is_root'] ? (array)$this->my_rights($mailbox) : array();
        $options['special']   = in_array($mailbox, $this->default_folders);
        // Set 'noselect' and 'norename' flags
        if (is_array($options['options'])) {
            foreach ($options['options'] as $opt) {
                $opt = strtolower($opt);
                if ($opt == '\noselect' || $opt == '\nonexistent') {
                    $options['noselect'] = true;
                }
            }
        }
        else {
            $options['noselect'] = true;
        }
        if (!empty($options['rights'])) {
            $options['norename'] = !in_array('x', $options['rights']);
            if (!$options['noselect']) {
                $options['noselect'] = !in_array('r', $options['rights']);
            }
        }
        else {
            $options['norename'] = $options['is_root'] || $options['namespace'] != 'personal';
        }
        $this->icache['options'] = $options;
        return $options;
    }
@@ -3744,16 +3840,28 @@
    function set_caching($type)
    {
        if ($type) {
            $rcmail = rcmail::get_instance();
            $this->cache = $rcmail->get_cache('IMAP', $type);
            $this->caching = true;
        }
        else {
            if ($this->cache)
                $this->cache->close();
            $this->cache = null;
            $this->caching = false;
        }
    }
    /**
     * Getter for IMAP cache object
     */
    private function get_cache_engine()
    {
        if ($this->caching && !$this->cache) {
            $rcmail = rcmail::get_instance();
            $this->cache = $rcmail->get_cache('IMAP', $type);
        }
        return $this->cache;
    }
    /**
     * Returns cached value
@@ -3764,8 +3872,8 @@
     */
    function get_cache($key)
    {
        if ($this->cache) {
            return $this->cache->get($key);
        if ($cache = $this->get_cache_engine()) {
            return $cache->get($key);
        }
    }
@@ -3778,23 +3886,23 @@
     */
    function update_cache($key, $data)
    {
        if ($this->cache) {
            $this->cache->set($key, $data);
        if ($cache = $this->get_cache_engine()) {
            $cache->set($key, $data);
        }
    }
    /**
     * Clears the cache.
     *
     * @param string  $key          Cache key name or pattern
     * @param boolean $pattern_mode Enable it to clear all keys with name
     *                              matching PREG pattern in $key
     * @param string  $key         Cache key name or pattern
     * @param boolean $prefix_mode Enable it to clear all keys starting
     *                             with prefix specified in $key
     * @access public
     */
    function clear_cache($key=null, $pattern_mode=false)
    function clear_cache($key=null, $prefix_mode=false)
    {
        if ($this->cache) {
            $this->cache->remove($key, $pattern_mode);
        if ($cache = $this->get_cache_engine()) {
            $cache->remove($key, $prefix_mode);
        }
    }
@@ -4585,7 +4693,7 @@
        // clear cached mailbox list(s)
        if ($updated) {
            $this->clear_cache('/^mailboxes.*/', true);
            $this->clear_cache('mailboxes', true);
        }
        return $updated;
@@ -4674,16 +4782,19 @@
        $str = self::explode_header_string(',;', $str, true);
        $result = array();
        // simplified regexp, supporting quoted local part
        $email_rx = '(\S+|("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+"))@\S+';
        foreach ($str as $key => $val) {
            $name    = '';
            $address = '';
            $val     = trim($val);
            if (preg_match('/(.*)<(\S+@\S+)>$/', $val, $m)) {
            if (preg_match('/(.*)<('.$email_rx.')>$/', $val, $m)) {
                $address = $m[2];
                $name    = trim($m[1]);
            }
            else if (preg_match('/^(\S+@\S+)$/', $val, $m)) {
            else if (preg_match('/^('.$email_rx.')$/', $val, $m)) {
                $address = $m[1];
                $name    = '';
            }
@@ -4693,7 +4804,7 @@
            // dequote and/or decode name
            if ($name) {
                if ($name[0] == '"') {
                if ($name[0] == '"' && $name[strlen($name)-1] == '"') {
                    $name = substr($name, 1, -1);
                    $name = stripslashes($name);
                }