thomascube
2010-06-08 af3cf8a0a7de74ab169f44277eda73f5f9e18cd7
program/include/rcube_imap.php
@@ -297,7 +297,9 @@
    {
        if (is_array($str) && $msgs == null)
            list($str, $msgs, $charset, $sort_field, $threads) = $str;
        if ($msgs != null && !is_array($msgs))
        if ($msgs === false)
            $msgs = array();
        else if ($msgs != null && !is_array($msgs))
            $msgs = explode(',', $msgs);
        $this->search_string     = $str;
@@ -474,11 +476,7 @@
                $search_str .= " UNSEEN";
            // get message count using SEARCH
            // not very performant but more precise (using UNDELETED)
            // disable THREADS for this request
            $threads = $this->threading;
            $this->threading = false;
            $index = $this->_search_index($mailbox, $search_str);
            $this->threading = $threads;
            $index = $this->conn->search($mailbox, $search_str);
            $count = is_array($index) ? count($index) : 0;
@@ -607,7 +605,7 @@
            else
                $msg_index = array();
            if ($slice)
            if ($slice && $msg_index)
                $msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice);
            // fetch reqested headers from server
@@ -822,8 +820,11 @@
            return $this->_list_thread_header_set($mailbox, $page, $sort_field, $sort_order, $slice);
        // search set is threaded, we need a new one
        if ($this->search_threads)
        if ($this->search_threads) {
            if (empty($this->search_set['tree']))
                return array();
            $this->search('', $this->search_string, $this->search_charset, $sort_field);
        }
        $msgs = $this->search_set;
        $a_msg_headers = array();
@@ -945,8 +946,15 @@
    private function _list_thread_header_set($mailbox, $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0)
    {
        // update search_set if previous data was fetched with disabled threading
        if (!$this->search_threads)
        if (!$this->search_threads) {
            if (empty($this->search_set))
                return array();
            $this->search('', $this->search_string, $this->search_charset, $sort_field);
        }
        // empty result
        if (empty($this->search_set['tree']))
            return array();
        $thread_tree = $this->search_set['tree'];
        $msg_depth = $this->search_set['depth'];
@@ -1187,20 +1195,20 @@
                $a_index = range(1, $max);
            }
            if ($this->sort_order == 'DESC')
            if ($a_index !== false && $this->sort_order == 'DESC')
                $a_index = array_reverse($a_index);
            $this->cache[$key] = $a_index;
        }
        // fetch complete message index
        else if ($this->get_capability('SORT')) {
            if ($a_index = $this->conn->sort($mailbox,
                $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '')) {
                if ($this->sort_order == 'DESC')
                    $a_index = array_reverse($a_index);
            $a_index = $this->conn->sort($mailbox,
                $this->sort_field, $this->skip_deleted ? 'UNDELETED' : '');
                $this->cache[$key] = $a_index;
           }
            if ($a_index !== false && $this->sort_order == 'DESC')
                $a_index = array_reverse($a_index);
            $this->cache[$key] = $a_index;
        }
        else if ($a_index = $this->conn->fetchHeaderIndex(
            $mailbox, "1:*", $this->sort_field, $this->skip_deleted)) {
@@ -1212,7 +1220,7 @@
            $this->cache[$key] = array_keys($a_index);
        }
        return $this->cache[$key];
        return $this->cache[$key] !== false ? $this->cache[$key] : array();
    }
@@ -1369,32 +1377,6 @@
        $results = $this->_search_index($mailbox, $str, $charset, $sort_field);
        // try search with US-ASCII charset (should be supported by server)
        // only if UTF-8 search is not supported
        if (empty($results) && !is_array($results) && !empty($charset) && $charset != 'US-ASCII')
        {
            // convert strings to US_ASCII
            if(preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) {
                $last = 0; $res = '';
                foreach($matches[1] as $m)
                {
                    $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
                    $string = substr($str, $string_offset - 1, $m[0]);
                    $string = rcube_charset_convert($string, $charset, 'US-ASCII');
                    if (!$string)
                        continue;
                    $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string);
                    $last = $m[0] + $string_offset - 1;
                }
                if ($last < strlen($str))
                    $res .= substr($str, $last, strlen($str)-$last);
            }
            else // strings for conversion not found
                $res = $str;
            $results = $this->search($mbox_name, $res, NULL, $sort_field);
        }
        $this->set_search_set($str, $results, $charset, $sort_field, (bool)$this->threading);
        return $results;
@@ -1416,21 +1398,32 @@
            $criteria = 'UNDELETED '.$criteria;
        if ($this->threading) {
            list ($thread_tree, $msg_depth, $has_children) = $this->conn->thread(
                $mailbox, $this->threading, $criteria, $charset);
            $a_messages = $this->conn->thread($mailbox, $this->threading, $criteria, $charset);
            $a_messages = array(
                'tree'    => $thread_tree,
               'depth'   => $msg_depth,
               'children' => $has_children
            );
            // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8,
            // but I've seen that Courier doesn't support UTF-8)
            if ($a_messages === false && $charset && $charset != 'US-ASCII')
                $a_messages = $this->conn->thread($mailbox, $this->threading,
                    $this->convert_criteria($criteria, $charset), 'US-ASCII');
            if ($a_messages !== false) {
                list ($thread_tree, $msg_depth, $has_children) = $a_messages;
                $a_messages = array(
                    'tree'    => $thread_tree,
                   'depth'   => $msg_depth,
                   'children' => $has_children
                );
            }
        }
        else if ($sort_field && $this->get_capability('SORT')) {
            $charset = $charset ? $charset : $this->default_charset;
            $a_messages = $this->conn->sort($mailbox, $sort_field, $criteria, false, $charset);
            if (!$a_messages)
               return array();
            // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8,
            // but I've seen that Courier doesn't support UTF-8)
            if ($a_messages === false && $charset && $charset != 'US-ASCII')
                $a_messages = $this->conn->sort($mailbox, $sort_field,
                    $this->convert_criteria($criteria, $charset), false, 'US-ASCII');
        }
        else {
            if ($orig_criteria == 'ALL') {
@@ -1439,14 +1432,16 @@
            }
            else {
                $a_messages = $this->conn->search($mailbox,
                        ($charset ? "CHARSET $charset " : '') . $criteria);
                    ($charset ? "CHARSET $charset " : '') . $criteria);
           if (!$a_messages)
               return array();
                // Error, try with US-ASCII (some servers may support only US-ASCII)
                if ($a_messages === false && $charset && $charset != 'US-ASCII')
                    $a_messages = $this->conn->search($mailbox,
                        'CHARSET US-ASCII ' . $this->convert_criteria($criteria, $charset));
            // I didn't found that SEARCH always returns sorted IDs
            if (!$this->sort_field)
                sort($a_messages);
                // I didn't found that SEARCH should return sorted IDs
               if (is_array($a_messages) && !$this->sort_field)
                    sort($a_messages);
            }
        }
@@ -1477,6 +1472,39 @@
        $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox;
        return $this->conn->search($mailbox, $str, $ret_uid);
    }
    /**
     * Converts charset of search criteria string
     *
     * @param  string  Search string
     * @param  string  Original charset
     * @param  string  Destination charset (default US-ASCII)
     * @return string  Search string
     * @access private
     */
    private function convert_criteria($str, $charset, $dest_charset='US-ASCII')
    {
        // convert strings to US_ASCII
        if (preg_match_all('/\{([0-9]+)\}\r\n/', $str, $matches, PREG_OFFSET_CAPTURE)) {
            $last = 0; $res = '';
            foreach ($matches[1] as $m) {
                $string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
                $string = substr($str, $string_offset - 1, $m[0]);
                $string = rcube_charset_convert($string, $charset, $dest_charset);
                if (!$string)
                    continue;
                $res .= sprintf("%s{%d}\r\n%s", substr($str, $last, $m[1] - $last - 1), strlen($string), $string);
                $last = $m[0] + $string_offset - 1;
            }
            if ($last < strlen($str))
                $res .= substr($str, $last, strlen($str)-$last);
        }
        else // strings for conversion not found
            $res = $str;
        return $res;
    }
@@ -1729,7 +1757,7 @@
            // build parts list for headers pre-fetching
            for ($i=0, $count=0; $i<count($part); $i++) {
                if (is_array($part[$i]) && count($part[$i]) > 3) {
                if (is_array($part[$i]) && count($part[$i]) > 4) {
                    // fetch message headers if message/rfc822
                    // or named part (could contain Content-Location header)
                    if (!is_array($part[$i][0])) {
@@ -1759,7 +1787,7 @@
            }
            $struct->parts = array();
            for ($i=0, $count=0; $i<count($part); $i++) {
                if (is_array($part[$i]) && count($part[$i]) > 3) {
                if (is_array($part[$i]) && count($part[$i]) > 4) {
                    $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
                    $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id,
                    $mime_part_headers[$tmp_part_id], $raw_part_headers[$tmp_part_id]);
@@ -2033,7 +2061,7 @@
            return true;
        // convert charset (if text or message part)
        if ($o_part->ctype_primary == 'text' || $o_part->ctype_primary == 'message') {
        if ($body && ($o_part->ctype_primary == 'text' || $o_part->ctype_primary == 'message')) {
            // assume default if no charset specified
            if (empty($o_part->charset) || strtolower($o_part->charset) == 'us-ascii')
                $o_part->charset = $this->default_charset;
@@ -2600,7 +2628,7 @@
            // retrieve list of folders from IMAP server
            $a_mboxes = $this->conn->listMailboxes($this->mod_mailbox($root), $filter);
        }
        $a_folders = array();
        if (!is_array($a_mboxes))
            $a_mboxes = array();