From bffca14d964091b3256868bc42bcb9417a72629b Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Tue, 19 Jan 2016 03:37:29 -0500 Subject: [PATCH] Exit when imagecreatetruecolor() fails --- program/lib/Roundcube/rcube_imap.php | 949 ++++++++++++++++++++++++++++------------------------------ 1 files changed, 457 insertions(+), 492 deletions(-) diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index f60be62..5f532a5 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -1,6 +1,6 @@ <?php -/* +/** +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | | Copyright (C) 2005-2012, The Roundcube Dev Team | @@ -56,14 +56,12 @@ */ protected $icache = array(); - protected $list_page = 1; + protected $plugins; protected $delimiter; protected $namespace; protected $sort_field = ''; protected $sort_order = 'DESC'; protected $struct_charset; - protected $uid_id_map = array(); - protected $msg_headers = array(); protected $search_set; protected $search_string = ''; protected $search_charset = ''; @@ -81,7 +79,8 @@ */ public function __construct() { - $this->conn = new rcube_imap_generic(); + $this->conn = new rcube_imap_generic(); + $this->plugins = rcube::get_instance()->plugins; // Set namespace and delimiter from session, // so some methods would work before connection @@ -92,7 +91,6 @@ $this->delimiter = $_SESSION['imap_delimiter']; } } - /** * Magic getter for backward compat. @@ -106,17 +104,16 @@ } } - /** * Connect to an IMAP server * - * @param string $host Host to connect - * @param string $user Username for IMAP account - * @param string $pass Password for IMAP account - * @param integer $port Port to connect to - * @param string $use_ssl SSL schema (either ssl or tls) or null if plain connection + * @param string $host Host to connect + * @param string $user Username for IMAP account + * @param string $pass Password for IMAP account + * @param integer $port Port to connect to + * @param string $use_ssl SSL schema (either ssl or tls) or null if plain connection * - * @return boolean TRUE on success, FALSE on failure + * @return boolean True on success, False on failure */ public function connect($host, $user, $pass, $port=143, $use_ssl=null) { @@ -147,7 +144,7 @@ $attempt = 0; do { - $data = rcube::get_instance()->plugins->exec_hook('storage_connect', + $data = $this->plugins->exec_hook('storage_connect', array_merge($this->options, array('host' => $host, 'user' => $user, 'attempt' => ++$attempt))); @@ -170,8 +167,20 @@ $this->connect_done = true; if ($this->conn->connected()) { + // check for session identifier + $session = null; + if (preg_match('/\s+SESSIONID=([^=\s]+)/', $this->conn->result, $m)) { + $session = $m[1]; + } + // get namespace and delimiter $this->set_env(); + + // trigger post-connect hook + $this->plugins->exec_hook('storage_connected', array( + 'host' => $host, 'user' => $user, 'session' => $session + )); + return true; } // write error log @@ -189,7 +198,6 @@ return false; } - /** * Close IMAP connection. * Usually done on script shutdown @@ -201,7 +209,6 @@ $this->mcache->close(); } } - /** * Check connection state, connect if not connected. @@ -224,7 +231,6 @@ return $this->is_connected(); } - /** * Checks IMAP connection. * @@ -234,7 +240,6 @@ { return $this->conn->connected(); } - /** * Returns code of last error @@ -246,7 +251,6 @@ return $this->conn->errornum; } - /** * Returns text of last error * @@ -256,7 +260,6 @@ { return $this->conn->error; } - /** * Returns code of last command response @@ -287,7 +290,6 @@ } } - /** * Activate/deactivate debug mode * @@ -299,23 +301,21 @@ $this->conn->setDebug($dbg, array($this, 'debug_handler')); } - /** * Set internal folder reference. * All operations will be perfomed on this folder. * - * @param string $folder Folder name + * @param string $folder Folder name */ public function set_folder($folder) { $this->folder = $folder; } - /** * Save a search result for future message listing methods * - * @param array $set Search set, result from rcube_imap::get_search_set(): + * @param array $set Search set, result from rcube_imap::get_search_set(): * 0 - searching criteria, string * 1 - search result, rcube_result_index|rcube_result_thread * 2 - searching character set, string @@ -338,7 +338,6 @@ } } - /** * Return the saved search set as hash array * @@ -358,7 +357,6 @@ $this->search_sorted, ); } - /** * Returns the IMAP server's capability. @@ -383,14 +381,13 @@ return $_SESSION[$sess_key]; } - /** * Checks the PERMANENTFLAGS capability of the current folder * and returns true if the given flag is supported by the IMAP server * - * @param string $flag Permanentflag name + * @param string $flag Permanentflag name * - * @return boolean True if this flag is supported + * @return boolean True if this flag is supported */ public function check_permflag($flag) { @@ -401,11 +398,10 @@ return $imap_flag && !empty($perm_flags) && in_array_nocase($imap_flag, $perm_flags); } - /** * Returns PERMANENTFLAGS of the specified folder * - * @param string $folder Folder name + * @param string $folder Folder name * * @return array Flags */ @@ -433,25 +429,22 @@ return $permflags; } - /** * Returns the delimiter that is used by the IMAP server for folder separation * - * @return string Delimiter string - * @access public + * @return string Delimiter string */ public function get_hierarchy_delimiter() { return $this->delimiter; } - /** * Get namespace * * @param string $name Namespace array index: personal, other, shared, prefix * - * @return array Namespace data + * @return array Namespace data */ public function get_namespace($name = null) { @@ -465,7 +458,6 @@ return $ns; } - /** * Sets delimiter and namespaces */ @@ -475,7 +467,7 @@ return; } - $config = rcube::get_instance()->config; + $config = rcube::get_instance()->config; $imap_personal = $config->get('imap_ns_personal'); $imap_other = $config->get('imap_ns_other'); $imap_shared = $config->get('imap_ns_shared'); @@ -546,6 +538,51 @@ $_SESSION['imap_delimiter'] = $this->delimiter; } + /** + * Returns IMAP server vendor name + * + * @return string Vendor name + * @since 1.2 + */ + public function get_vendor() + { + if ($_SESSION['imap_vendor'] !== null) { + return $_SESSION['imap_vendor']; + } + + $config = rcube::get_instance()->config; + $imap_vendor = $config->get('imap_vendor'); + + if ($imap_vendor) { + return $imap_vendor; + } + + if (!$this->check_connection()) { + return; + } + + if (($ident = $this->conn->data['ID']) === null) { + $ident = $this->conn->id(array( + 'name' => 'Roundcube', + 'version' => RCUBE_VERSION, + 'php' => PHP_VERSION, + 'os' => PHP_OS, + )); + } + + $vendor = (string) (!empty($ident) ? $ident['name'] : ''); + $ident = strtolower($vendor . ' ' . $this->conn->data['GREETING']); + $vendors = array('cyrus', 'dovecot', 'uw-imap', 'gmail', 'hmail'); + + foreach ($vendors as $v) { + if (strpos($ident, $v) !== false) { + $vendor = $v; + break; + } + } + + return $_SESSION['imap_vendor'] = $vendor; + } /** * Get message count for a specific folder @@ -556,7 +593,7 @@ * @param boolean $status Enables storing folder status info (max UID/count), * required for folder_status() * - * @return int Number of messages + * @return int Number of messages */ public function count($folder='', $mode='ALL', $force=false, $status=true) { @@ -567,29 +604,31 @@ return $this->countmessages($folder, $mode, $force, $status); } - /** - * protected method for getting nr of messages + * Protected method for getting number of messages * - * @param string $folder Folder name - * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS] - * @param boolean $force Force reading from server and update cache - * @param boolean $status Enables storing folder status info (max UID/count), - * required for folder_status() + * @param string $folder Folder name + * @param string $mode Mode for count [ALL|THREADS|UNSEEN|RECENT|EXISTS] + * @param boolean $force Force reading from server and update cache + * @param boolean $status Enables storing folder status info (max UID/count), + * required for folder_status() + * @param boolean $no_search Ignore current search result * * @return int Number of messages * @see rcube_imap::count() */ - protected function countmessages($folder, $mode='ALL', $force=false, $status=true) + protected function countmessages($folder, $mode = 'ALL', $force = false, $status = true, $no_search = false) { $mode = strtoupper($mode); - // count search set, assume search set is always up-to-date (don't check $force flag) - if ($this->search_string && $folder == $this->folder && ($mode == 'ALL' || $mode == 'THREADS')) { + // Count search set, assume search set is always up-to-date (don't check $force flag) + // @TODO: this could be handled in more reliable way, e.g. a separate method + // maybe in rcube_imap_search + if (!$no_search && $this->search_string && $folder == $this->folder) { if ($mode == 'ALL') { return $this->search_set->count_messages(); } - else { + else if ($mode == 'THREADS') { return $this->search_set->count(); } } @@ -682,7 +721,6 @@ return (int)$count; } - /** * Public method for listing message flags * @@ -717,7 +755,6 @@ return $result; } - /** * Public method for listing headers * @@ -727,7 +764,7 @@ * @param string $sort_order Sort order [ASC|DESC] * @param int $slice Number of slice items to extract from result array * - * @return array Indexed array with message header objects + * @return array Indexed array with message header objects */ public function list_messages($folder='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0) { @@ -738,7 +775,6 @@ return $this->_list_messages($folder, $page, $sort_field, $sort_order, $slice); } - /** * protected method for listing message headers * @@ -748,8 +784,8 @@ * @param string $sort_order Sort order [ASC|DESC] * @param int $slice Number of slice items to extract from result array * - * @return array Indexed array with message header objects - * @see rcube_imap::list_messages + * @return array Indexed array with message header objects + * @see rcube_imap::list_messages */ protected function _list_messages($folder='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0) { @@ -761,7 +797,7 @@ $page = $page ? $page : $this->list_page; // use saved message set - if ($this->search_string && $folder == $this->folder) { + if ($this->search_string) { return $this->list_search_messages($folder, $page, $slice); } @@ -792,16 +828,15 @@ return array_values($a_msg_headers); } - /** * protected method for listing message headers using threads * - * @param string $folder Folder name - * @param int $page Current page to list - * @param int $slice Number of slice items to extract from result array + * @param string $folder Folder name + * @param int $page Current page to list + * @param int $slice Number of slice items to extract from result array * - * @return array Indexed array with message header objects - * @see rcube_imap::list_messages + * @return array Indexed array with message header objects + * @see rcube_imap::list_messages */ protected function list_thread_messages($folder, $page, $slice=0) { @@ -819,7 +854,7 @@ /** * Method for fetching threads data * - * @param string $folder Folder name + * @param string $folder Folder name * * @return rcube_imap_thread Thread data object */ @@ -843,11 +878,10 @@ return $this->icache['threads'] = $result; } - /** * Method for direct fetching of threads data * - * @param string $folder Folder name + * @param string $folder Folder name * * @return rcube_imap_thread Thread data object */ @@ -862,7 +896,6 @@ $this->options['skip_deleted'] ? 'UNDELETED' : '', true); } - /** * protected method for fetching threaded messages headers * @@ -871,7 +904,7 @@ * @param int $page List page number * @param int $slice Number of threads to slice * - * @return array Messages headers + * @return array Messages headers */ protected function fetch_thread_headers($folder, $threads, $page, $slice=0) { @@ -901,13 +934,12 @@ return array_values($a_msg_headers); } - /** * protected method for setting threaded messages flags: * depth, has_children and unread_children * - * @param array $headers Reference to headers array indexed by message UID - * @param rcube_result_thread $threads Threads data object + * @param array $headers Reference to headers array indexed by message UID + * @param rcube_result_thread $threads Threads data object * * @return array Message headers array indexed by message UID */ @@ -933,7 +965,6 @@ } } - /** * protected method for listing a set of message headers (search results) * @@ -941,7 +972,7 @@ * @param int $page Current page to list * @param int $slice Number of slice items to extract from result array * - * @return array Indexed array with message header objects + * @return array Indexed array with message header objects */ protected function list_search_messages($folder, $page, $slice=0) { @@ -951,39 +982,63 @@ // gather messages from a multi-folder search if ($this->search_set->multi) { - $page_size = $this->page_size; + $page_size = $this->page_size; $sort_field = $this->sort_field; $search_set = $this->search_set; - $this->sort_field = null; - $this->page_size = 1000; // fetch up to 1000 matching messages per folder - $this->threading = false; - - $a_msg_headers = array(); - foreach ($search_set->sets as $resultset) { - if (!$resultset->is_empty()) { - $this->search_set = $resultset; - $this->search_threads = $resultset instanceof rcube_result_thread; - $a_msg_headers = array_merge($a_msg_headers, $this->list_search_messages($resultset->get_parameters('MAILBOX'), 1)); - } - } - - // do sorting and paging + // prepare paging $cnt = $search_set->count(); $from = ($page-1) * $page_size; $to = $from + $page_size; + $slice_length = min($page_size, $cnt - $from); - // sort headers - if (!$this->threading && !empty($a_msg_headers)) { - $a_msg_headers = $this->conn->sortHeaders($a_msg_headers, $sort_field, $this->sort_order); + // fetch resultset headers, sort and slice them + if (!empty($sort_field) && $search_set->get_parameters('SORT') != $sort_field) { + $this->sort_field = null; + $this->page_size = 1000; // fetch up to 1000 matching messages per folder + $this->threading = false; + + $a_msg_headers = array(); + foreach ($search_set->sets as $resultset) { + if (!$resultset->is_empty()) { + $this->search_set = $resultset; + $this->search_threads = $resultset instanceof rcube_result_thread; + + $a_headers = $this->list_search_messages($resultset->get_parameters('MAILBOX'), 1); + $a_msg_headers = array_merge($a_msg_headers, $a_headers); + unset($a_headers); + } + } + + // sort headers + if (!empty($a_msg_headers)) { + $a_msg_headers = rcube_imap_generic::sortHeaders($a_msg_headers, $sort_field, $this->sort_order); + } + + // store (sorted) message index + $search_set->set_message_index($a_msg_headers, $sort_field, $this->sort_order); + + // only return the requested part of the set + $a_msg_headers = array_slice(array_values($a_msg_headers), $from, $slice_length); } + else { + if ($this->sort_order != $search_set->get_parameters('ORDER')) { + $search_set->revert(); + } - // store (sorted) message index - $search_set->set_message_index($a_msg_headers, $sort_field, $this->sort_order); + // slice resultset first... + $fetch = array(); + foreach (array_slice($search_set->get(), $from, $slice_length) as $msg_id) { + list($uid, $folder) = explode('-', $msg_id, 2); + $fetch[$folder][] = $uid; + } - // only return the requested part of the set - $slice_length = min($page_size, $cnt - $from); - $a_msg_headers = array_slice(array_values($a_msg_headers), $from, $slice_length); + // ... and fetch the requested set of headers + $a_msg_headers = array(); + foreach ($fetch as $folder => $a_index) { + $a_msg_headers = array_merge($a_msg_headers, array_values($this->fetch_headers($folder, $a_index))); + } + } if ($slice) { $a_msg_headers = array_slice($a_msg_headers, -$slice, $slice); @@ -991,7 +1046,7 @@ // restore members $this->sort_field = $sort_field; - $this->page_size = $page_size; + $this->page_size = $page_size; $this->search_set = $search_set; return $a_msg_headers; @@ -1085,12 +1140,8 @@ return array(); } - if (!$this->check_connection()) { - return array(); - } - // if not already sorted - $a_msg_headers = $this->conn->sortHeaders( + $a_msg_headers = rcube_imap_generic::sortHeaders( $a_msg_headers, $this->sort_field, $this->sort_order); // only return the requested part of the set @@ -1105,7 +1156,6 @@ } } - /** * protected method for listing a set of threaded message headers (search results) * @@ -1113,7 +1163,7 @@ * @param int $page Current page to list * @param int $slice Number of slice items to extract from result array * - * @return array Indexed array with message header objects + * @return array Indexed array with message header objects * @see rcube_imap::list_search_messages() */ protected function list_search_thread_messages($folder, $page, $slice=0) @@ -1128,7 +1178,6 @@ return $this->fetch_thread_headers($folder, clone $this->search_set, $page, $slice); } - /** * Fetches messages headers (by UID) @@ -1177,7 +1226,6 @@ return $a_msg_headers; } - /** * Returns current status of a folder (compared to the last time use) * @@ -1197,7 +1245,7 @@ $old = $this->get_folder_stats($folder); // refresh message count -> will update - $this->countmessages($folder, 'ALL', true); + $this->countmessages($folder, 'ALL', true, true, true); $result = 0; @@ -1225,7 +1273,6 @@ return $result; } - /** * Stores folder statistic data in session * @TODO: move to separate DB table (cache?) @@ -1238,7 +1285,6 @@ { $_SESSION['folders'][$folder][$name] = $data; } - /** * Gets folder statistic data @@ -1255,7 +1301,6 @@ return array(); } - /** * Return sorted list of message UIDs @@ -1334,7 +1379,6 @@ return $this->index_direct($folder, $this->sort_field, $this->sort_order); } - /** * Return sorted list of message UIDs ignoring current search settings. * Doesn't uses cache by default. @@ -1349,7 +1393,7 @@ public function index_direct($folder, $sort_field = null, $sort_order = null, $search = null) { if (!empty($search)) { - $search = $this->search_set->get_compressed(); + $search = $search->get_compressed(); } // use message index sort as default sorting @@ -1402,7 +1446,6 @@ return $index; } - /** * Return index of threaded message UIDs * @@ -1433,7 +1476,6 @@ return $threads; } - /** * Sort threaded result, using THREAD=REFS method if available. * If not, use any method and re-sort the result in THREAD=REFS way. @@ -1463,32 +1505,43 @@ } } - /** * Invoke search request to IMAP server * * @param string $folder Folder name to search in - * @param string $str Search criteria + * @param string $search Search criteria * @param string $charset Search charset * @param string $sort_field Header field to sort by * + * @return rcube_result_index Search result object * @todo: Search criteria should be provided in non-IMAP format, eg. array */ - public function search($folder='', $str='ALL', $charset=NULL, $sort_field=NULL) + public function search($folder = '', $search = 'ALL', $charset = null, $sort_field = null) { - if (!$str) { - $str = 'ALL'; + if (!$search) { + $search = 'ALL'; } - if (empty($folder)) { + if ((is_array($folder) && empty($folder)) || (!is_array($folder) && !strlen($folder))) { $folder = $this->folder; } - // multi-folder search - if (is_array($folder) && count($folder) > 1 && $str != 'ALL') { - new rcube_result_index; // trigger autoloader and make these classes available for threaded context - new rcube_result_thread; + $plugin = $this->plugins->exec_hook('imap_search_before', array( + 'folder' => $folder, + 'search' => $search, + 'charset' => $charset, + 'sort_field' => $sort_field, + 'threading' => $this->threading, + )); + $folder = $plugin['folder']; + $search = $plugin['search']; + $charset = $plugin['charset']; + $sort_field = $plugin['sort_field']; + $results = $plugin['result']; + + // multi-folder search + if (!$results && is_array($folder) && count($folder) > 1 && $search != 'ALL') { // connect IMAP to have all the required classes and settings loaded $this->check_connection(); @@ -1496,23 +1549,36 @@ $this->threading = false; $searcher = new rcube_imap_search($this->options, $this->conn); + + // set limit to not exceed the client's request timeout + $searcher->set_timelimit(60); + + // continue existing incomplete search + if (!empty($this->search_set) && $this->search_set->incomplete && $search == $this->search_string) { + $searcher->set_results($this->search_set); + } + + // execute the search $results = $searcher->exec( $folder, - $str, + $search, $charset ? $charset : $this->default_charset, $sort_field && $this->get_capability('SORT') ? $sort_field : null, $this->threading ); } - else { - $folder = is_array($folder) ? $folder[0] : $folder; - $results = $this->search_index($folder, $str, $charset, $sort_field); + else if (!$results) { + $folder = is_array($folder) ? $folder[0] : $folder; + $search = is_array($search) ? $search[$folder] : $search; + $results = $this->search_index($folder, $search, $charset, $sort_field); } - $this->set_search_set(array($str, $results, $charset, $sort_field, - $this->threading || $this->search_sorted ? true : false)); - } + $sorted = $this->threading || $this->search_sorted || $plugin['search_sorted'] ? true : false; + $this->set_search_set(array($search, $results, $charset, $sort_field, $sorted)); + + return $results; + } /** * Direct (real and simple) SEARCH request (without result sorting and caching). @@ -1524,23 +1590,29 @@ */ public function search_once($folder = null, $str = 'ALL') { - if (!$str) { - $str = 'ALL'; - } - - if (!strlen($folder)) { - $folder = $this->folder; - } - if (!$this->check_connection()) { return new rcube_result_index(); } - $index = $this->conn->search($folder, $str, true); + if (!$str) { + $str = 'ALL'; + } + + // multi-folder search + if (is_array($folder) && count($folder) > 1) { + $searcher = new rcube_imap_search($this->options, $this->conn); + $index = $searcher->exec($folder, $str, $this->default_charset); + } + else { + $folder = is_array($folder) ? $folder[0] : $folder; + if (!strlen($folder)) { + $folder = $this->folder; + } + $index = $this->conn->search($folder, $str, true); + } return $index; } - /** * protected search method @@ -1618,7 +1690,6 @@ return $messages; } - /** * Converts charset of search criteria string * @@ -1637,12 +1708,15 @@ $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 === false) { + + if ($string === false || !strlen($string)) { continue; } + $res .= substr($str, $last, $m[1] - $last - 1) . rcube_imap_generic::escape($string); $last = $m[0] + $string_offset - 1; } + if ($last < strlen($str)) { $res .= substr($str, $last, strlen($str)-$last); } @@ -1655,7 +1729,6 @@ return $res; } - /** * Refresh saved search set * @@ -1664,13 +1737,29 @@ public function refresh_search() { if (!empty($this->search_string)) { - // FIXME: make this work with saved multi-folder searches - $this->search('', $this->search_string, $this->search_charset, $this->search_sort_field); + $this->search( + is_object($this->search_set) ? $this->search_set->get_parameters('MAILBOX') : '', + $this->search_string, + $this->search_charset, + $this->search_sort_field + ); } return $this->get_search_set(); } + /** + * Flag certain result subsets as 'incomplete'. + * For subsequent refresh_search() calls to only refresh the updated parts. + */ + protected function set_search_dirty($folder) + { + if ($this->search_set && is_a($this->search_set, 'rcube_result_multifolder')) { + if ($subset = $this->search_set->get_set($folder)) { + $subset->incomplete = $this->search_set->incomplete = true; + } + } + } /** * Return message headers object of a specific message @@ -1683,13 +1772,13 @@ */ public function get_message_headers($uid, $folder = null, $force = false) { - if (!strlen($folder)) { - $folder = $this->folder; + // decode combined UID-folder identifier + if (preg_match('/^\d+-.+/', $uid)) { + list($uid, $folder) = explode('-', $uid, 2); } - // decode combined UID-folder identifier - if (preg_match('/^\d+-[^,]+$/', $uid)) { - list($uid, $folder) = explode('-', $uid); + if (!strlen($folder)) { + $folder = $this->folder; } // get cached headers @@ -1702,18 +1791,20 @@ else { $headers = $this->conn->fetchHeader( $folder, $uid, true, true, $this->get_fetch_headers()); + + if (is_object($headers)) + $headers->folder = $folder; } return $headers; } - /** * Fetch message headers and body structure from the IMAP server and build - * an object structure similar to the one generated by PEAR::Mail_mimeDecode + * an object structure. * - * @param int $uid Message UID to fetch - * @param string $folder Folder to read from + * @param int $uid Message UID to fetch + * @param string $folder Folder to read from * * @return object rcube_message_header Message data */ @@ -1724,8 +1815,8 @@ } // decode combined UID-folder identifier - if (preg_match('/^\d+-[^,]+$/', $uid)) { - list($uid, $folder) = explode('-', $uid); + if (preg_match('/^\d+-.+/', $uid)) { + list($uid, $folder) = explode('-', $uid, 2); } // Check internal cache @@ -1771,7 +1862,7 @@ $this->struct_charset = $this->structure_charset($structure); } - $headers->ctype = strtolower($headers->ctype); + $headers->ctype = @strtolower($headers->ctype); // Here we can recognize malformed BODYSTRUCTURE and // 1. [@TODO] parse the message in other way to create our own message structure @@ -1792,8 +1883,8 @@ $structure[1] = $m[2]; } else { - // Try to parse the message using Mail_mimeDecode package - // We need a better solution, Mail_mimeDecode parses message + // Try to parse the message using rcube_mime_decode. + // We need a better solution, it parses message // in memory, which wouldn't work for very big messages, // (it uses up to 10x more memory than the message size) // it's also buggy and not actively developed @@ -1833,7 +1924,6 @@ return $this->icache['message'] = $headers; } - /** * Build message part object * @@ -1841,7 +1931,7 @@ * @param int $count * @param string $parent */ - protected function structure_part($part, $count=0, $parent='', $mime_headers=null) + protected function structure_part($part, $count = 0, $parent = '', $mime_headers = null) { $struct = new rcube_message_part; $struct->mime_id = empty($parent) ? (string)$count : "$parent.$count"; @@ -1866,6 +1956,16 @@ for ($i=1; $i<count($part); $i++) { if (!is_array($part[$i])) { $struct->ctype_secondary = strtolower($part[$i]); + + // read content type parameters + if (is_array($part[$i+1])) { + $struct->ctype_parameters = array(); + for ($j=0; $j<count($part[$i+1]); $j+=2) { + $param = strtolower($part[$i+1][$j]); + $struct->ctype_parameters[$param] = $part[$i+1][$j+1]; + } + } + break; } } @@ -2049,14 +2149,13 @@ return $struct; } - /** * Set attachment filename from message part structure * - * @param rcube_message_part $part Part object - * @param string $headers Part's raw headers + * @param rcube_message_part $part Part object + * @param string $headers Part's raw headers */ - protected function set_part_filename(&$part, $headers=null) + protected function set_part_filename(&$part, $headers = null) { if (!empty($part->d_parameters['filename'])) { $filename_mime = $part->d_parameters['filename']; @@ -2184,11 +2283,10 @@ } } - /** * Get charset name from message structure (first part) * - * @param array $structure Message structure + * @param array $structure Message structure * * @return string Charset name */ @@ -2217,7 +2315,8 @@ * * @return string Message/part body if not printed */ - public function get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false, $max_bytes=0, $formatted=true) + public function get_message_part($uid, $part = 1, $o_part = null, $print = null, $fp = null, + $skip_charset_conv = false, $max_bytes = 0, $formatted = true) { if (!$this->check_connection()) { return null; @@ -2269,42 +2368,41 @@ return $body; } - /** * Returns the whole message source as string (or saves to a file) * - * @param int $uid Message UID - * @param resource $fp File pointer to save the message + * @param int $uid Message UID + * @param resource $fp File pointer to save the message + * @param string $part Optional message part ID * * @return string Message source string */ - public function get_raw_body($uid, $fp=null) + public function get_raw_body($uid, $fp=null, $part = null) { if (!$this->check_connection()) { return null; } return $this->conn->handlePartBody($this->folder, $uid, - true, null, null, false, $fp); + true, $part, null, false, $fp); } - /** * Returns the message headers as string * - * @param int $uid Message UID + * @param int $uid Message UID + * @param string $part Optional message part ID * * @return string Message headers string */ - public function get_raw_headers($uid) + public function get_raw_headers($uid, $part = null) { if (!$this->check_connection()) { return null; } - return $this->conn->fetchPartHeader($this->folder, $uid, true); + return $this->conn->fetchPartHeader($this->folder, $uid, true, $part); } - /** * Sends the whole message source to stdout @@ -2321,13 +2419,12 @@ $this->conn->handlePartBody($this->folder, $uid, true, null, null, true, null, $formatted); } - /** * Set message flag to one or several messages * * @param mixed $uids Message UIDs as array or comma-separated string, or '*' * @param string $flag Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT, MDNSENT - * @param string $folder Folder name + * @param string $folder Folder name * @param boolean $skip_cache True to skip message cache clean up * * @return boolean Operation status @@ -2374,11 +2471,12 @@ $this->clear_message_cache($folder, $all_mode ? null : explode(',', $uids)); } } + + $this->set_search_dirty($folder); } return $result; } - /** * Append a mail message (source) to a specific folder @@ -2421,11 +2519,21 @@ if ($saved) { // increase messagecount of the target folder $this->set_messagecount($folder, 'ALL', 1); + + $this->plugins->exec_hook('message_saved', array( + 'folder' => $folder, + 'message' => $message, + 'headers' => $headers, + 'is_file' => $is_file, + 'flags' => $flags, + 'date' => $date, + 'binary' => $binary, + 'result' => $saved, + )); } return $saved; } - /** * Move a message from one folder to another @@ -2472,6 +2580,9 @@ if ($moved) { $this->clear_messagecount($from_mbox); $this->clear_messagecount($to_mbox); + + $this->set_search_dirty($from_mbox); + $this->set_search_dirty($to_mbox); } // moving failed else if ($to_trash && $config->get('delete_always', false)) { @@ -2488,7 +2599,7 @@ if ($this->search_threads || $all_mode) { $this->refresh_search(); } - else { + else if (!$this->search_set->incomplete) { $this->search_set->filter(explode(',', $uids), $this->folder); } } @@ -2500,7 +2611,6 @@ return $moved; } - /** * Copy a message from one folder to another @@ -2538,7 +2648,6 @@ return $copied; } - /** * Mark messages as deleted and expunge them * @@ -2571,10 +2680,11 @@ // really deleted from the folder $this->expunge_message($uids, $folder, false); $this->clear_messagecount($folder); - unset($this->uid_id_map[$folder]); // unset threads internal cache unset($this->icache['threads']); + + $this->set_search_dirty($folder); // remove message ids from search set if ($this->search_set && $folder == $this->folder) { @@ -2582,7 +2692,7 @@ if ($this->search_threads || $all_mode) { $this->refresh_search(); } - else { + else if (!$this->search_set->incomplete) { $this->search_set->filter(explode(',', $uids)); } } @@ -2593,7 +2703,6 @@ return $deleted; } - /** * Send IMAP expunge command and clear cache @@ -2682,7 +2791,7 @@ } // Give plugins a chance to provide a list of folders - $data = rcube::get_instance()->plugins->exec_hook('storage_folders', + $data = $this->plugins->exec_hook('storage_folders', array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LSUB')); if (isset($data['folders'])) { @@ -2702,7 +2811,7 @@ } // INBOX should always be available - if ((!$filter || $filter == 'mail') && !in_array('INBOX', $a_mboxes)) { + if (!strlen($root) && (!$filter || $filter == 'mail') && !in_array('INBOX', $a_mboxes)) { array_unshift($a_mboxes, 'INBOX'); } @@ -2717,15 +2826,14 @@ return $a_mboxes; } - /** * Method for direct folders listing (LSUB) * - * @param string $root Optional root folder - * @param string $name Optional name pattern + * @param string $root Optional root folder + * @param string $name Optional name pattern * - * @return array List of subscribed folders - * @see rcube_imap::list_folders_subscribed() + * @return array List of subscribed folders + * @see rcube_imap::list_folders_subscribed() */ public function list_folders_subscribed_direct($root='', $name='*') { @@ -2740,42 +2848,47 @@ $list_extended = !$config->get('imap_force_lsub') && $this->get_capability('LIST-EXTENDED'); if ($list_extended) { // This will also set folder options, LSUB doesn't do that - $a_folders = $this->conn->listMailboxes($root, $name, + $result = $this->conn->listMailboxes($root, $name, NULL, array('SUBSCRIBED')); } else { // retrieve list of folders from IMAP server using LSUB - $a_folders = $this->conn->listSubscribed($root, $name); + $result = $this->conn->listSubscribed($root, $name); } - if (!is_array($a_folders)) { + if (!is_array($result)) { return array(); } // #1486796: some server configurations doesn't return folders in all namespaces if ($root == '' && $name == '*' && $config->get('imap_force_ns')) { - $this->list_folders_update($a_folders, ($list_extended ? 'ext-' : '') . 'subscribed'); + $this->list_folders_update($result, ($list_extended ? 'ext-' : '') . 'subscribed'); + } + + // Remove hidden folders + if ($config->get('imap_skip_hidden_folders')) { + $result = array_filter($result, function($v) { return $v[0] != '.'; }); } if ($list_extended) { // unsubscribe non-existent folders, remove from the list - if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) { - foreach ($a_folders as $idx => $folder) { + if ($name == '*' && !empty($this->conn->data['LIST'])) { + foreach ($result as $idx => $folder) { if (($opts = $this->conn->data['LIST'][$folder]) - && in_array('\\NonExistent', $opts) + && in_array_nocase('\\NonExistent', $opts) ) { $this->conn->unsubscribe($folder); - unset($a_folders[$idx]); + unset($result[$idx]); } } } } else { // unsubscribe non-existent folders, remove them from the list - if (is_array($a_folders) && !empty($a_folders) && $name == '*') { + if (!empty($result) && $name == '*') { $existing = $this->list_folders($root, $name); - $nonexisting = array_diff($a_folders, $existing); - $a_folders = array_diff($a_folders, $nonexisting); + $nonexisting = array_diff($result, $existing); + $result = array_diff($result, $nonexisting); foreach ($nonexisting as $folder) { $this->conn->unsubscribe($folder); @@ -2783,9 +2896,8 @@ } } - return $a_folders; + return $result; } - /** * Get a list of all folders available on the server @@ -2814,7 +2926,7 @@ } // Give plugins a chance to provide a list of folders - $data = rcube::get_instance()->plugins->exec_hook('storage_folders', + $data = $this->plugins->exec_hook('storage_folders', array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LIST')); if (isset($data['folders'])) { @@ -2830,7 +2942,7 @@ } // INBOX should always be available - if ((!$filter || $filter == 'mail') && !in_array('INBOX', $a_mboxes)) { + if (!strlen($root) && (!$filter || $filter == 'mail') && !in_array('INBOX', $a_mboxes)) { array_unshift($a_mboxes, 'INBOX'); } @@ -2855,15 +2967,14 @@ return $a_mboxes; } - /** * Method for direct folders listing (LIST) * - * @param string $root Optional root folder - * @param string $name Optional name pattern + * @param string $root Optional root folder + * @param string $name Optional name pattern * - * @return array List of folders - * @see rcube_imap::list_folders() + * @return array List of folders + * @see rcube_imap::list_folders() */ public function list_folders_direct($root='', $name='*') { @@ -2884,18 +2995,22 @@ $this->list_folders_update($result); } + // Remove hidden folders + if ($config->get('imap_skip_hidden_folders')) { + $result = array_filter($result, function($v) { return $v[0] != '.'; }); + } + return $result; } - /** * Fix folders list by adding folders from other namespaces. * Needed on some servers eg. Courier IMAP * - * @param array $result Reference to folders list - * @param string $type Listing type (ext-subscribed, subscribed or all) + * @param array $result Reference to folders list + * @param string $type Listing type (ext-subscribed, subscribed or all) */ - private function list_folders_update(&$result, $type = null) + protected function list_folders_update(&$result, $type = null) { $namespace = $this->get_namespace(); $search = array(); @@ -2943,7 +3058,6 @@ } } - /** * Filter the given list of folders according to access rights * @@ -2969,22 +3083,21 @@ return $a_folders; } - /** * Get mailbox quota information - * added by Nuny + * + * @param string $folder Folder name * * @return mixed Quota info or False if not supported */ - public function get_quota() + public function get_quota($folder = null) { if ($this->get_capability('QUOTA') && $this->check_connection()) { - return $this->conn->getQuota(); + return $this->conn->getQuota($folder); } return false; } - /** * Get folder size (size of all messages in a folder) @@ -2995,8 +3108,22 @@ */ public function folder_size($folder) { + if (!strlen($folder)) { + return false; + } + if (!$this->check_connection()) { return 0; + } + + // On Cyrus we can use special folder annotation, which should be much faster + if ($this->get_vendor() == 'cyrus') { + $idx = '/shared/vendor/cmu/cyrus-imapd/size'; + $result = $this->get_metadata($folder, $idx, array(), true); + + if (!empty($result) && is_numeric($result[$folder][$idx])) { + return $result[$folder][$idx]; + } } // @TODO: could we try to use QUOTA here? @@ -3008,7 +3135,6 @@ return $result; } - /** * Subscribe to a specific folder(s) @@ -3023,7 +3149,6 @@ return $this->change_subscription($folders, 'subscribe'); } - /** * Unsubscribe folder(s) * @@ -3036,7 +3161,6 @@ // let this common function do the main work return $this->change_subscription($folders, 'unsubscribe'); } - /** * Create a new folder on the server and register it in local cache @@ -3067,7 +3191,6 @@ return $result; } - /** * Set a new name to an existing folder @@ -3128,7 +3251,6 @@ return $result; } - /** * Remove folder from server * @@ -3176,7 +3298,6 @@ return $result; } - /** * Detect special folder associations stored in storage backend */ @@ -3202,12 +3323,14 @@ // request \Subscribed flag in LIST response as performance improvement for folder_exists() $folders = $this->conn->listMailboxes('', '*', array('SUBSCRIBED'), array('SPECIAL-USE')); - foreach ($folders as $folder) { - if ($flags = $this->conn->data['LIST'][$folder]) { - foreach ($types as $type) { - if (in_array($type, $flags)) { - $type = strtolower(substr($type, 1)); - $special[$type] = $folder; + if (!empty($folders)) { + foreach ($folders as $folder) { + if ($flags = $this->conn->data['LIST'][$folder]) { + foreach ($types as $type) { + if (in_array($type, $flags)) { + $type = strtolower(substr($type, 1)); + $special[$type] = $folder; + } } } } @@ -3218,7 +3341,6 @@ return array_merge($result, $special); } - /** * Set special folder associations stored in storage backend @@ -3258,7 +3380,6 @@ return true; } - /** * Checks if folder exists and is subscribed * @@ -3286,7 +3407,7 @@ if ($subscription) { // It's possible we already called LIST command, check LIST data if (!empty($this->conn->data['LIST']) && !empty($this->conn->data['LIST'][$folder]) - && in_array('\\Subscribed', $this->conn->data['LIST'][$folder]) + && in_array_nocase('\\Subscribed', $this->conn->data['LIST'][$folder]) ) { $a_folders = array($folder); } @@ -3311,7 +3432,6 @@ return false; } - /** * Returns the namespace where the folder is in @@ -3342,7 +3462,6 @@ return 'personal'; } - /** * Modify folder name according to namespace. @@ -3382,7 +3501,6 @@ return $folder; } - /** * Gets folder attributes from LIST response, e.g. \Noselect, \Noinferiors * @@ -3414,7 +3532,6 @@ return is_array($opts) ? $opts : array(); } - /** * Gets connection (and current folder) data: UIDVALIDITY, EXISTS, RECENT, @@ -3454,7 +3571,6 @@ return $data; } - /** * Returns extended information about the folder @@ -3551,7 +3667,6 @@ return $options; } - /** * Synchronizes messages cache. * @@ -3563,7 +3678,6 @@ $mcache->synchronize($folder); } } - /** * Get message header names for rcube_imap_generic::fetchHeader(s) @@ -3616,7 +3730,6 @@ return $this->conn->setACL($folder, $user, $acl); } - /** * Removes any <identifier,rights> pair for the * specified user from the ACL for the specified @@ -3641,7 +3754,6 @@ return $this->conn->deleteACL($folder, $user); } - /** * Returns the access control list for folder (GETACL) * @@ -3662,7 +3774,6 @@ return $this->conn->getACL($folder); } - /** * Returns information about what rights can be granted to the @@ -3687,7 +3798,6 @@ return $this->conn->listRights($folder, $user); } - /** * Returns the set of rights that the current user has to * folder (MYRIGHTS) @@ -3709,7 +3819,6 @@ return $this->conn->myRights($folder); } - /** * Sets IMAP metadata/annotations (SETMETADATA/SETANNOTATION) @@ -3744,7 +3853,6 @@ return false; } - /** * Unsets IMAP metadata/annotations (SETMETADATA/SETANNOTATION) * @@ -3778,34 +3886,36 @@ return false; } - /** * Returns IMAP metadata/annotations (GETMETADATA/GETANNOTATION) * - * @param string $folder Folder name (empty for server metadata) - * @param array $entries Entries - * @param array $options Command options (with MAXSIZE and DEPTH keys) + * @param string $folder Folder name (empty for server metadata) + * @param array $entries Entries + * @param array $options Command options (with MAXSIZE and DEPTH keys) + * @param bool $force Disables cache use * * @return array Metadata entry-value hash array on success, NULL on error * @since 0.5-beta */ - public function get_metadata($folder, $entries, $options=array()) + public function get_metadata($folder, $entries, $options = array(), $force = false) { - $entries = (array)$entries; + $entries = (array) $entries; - // create cache key - // @TODO: this is the simplest solution, but we do the same with folders list - // maybe we should store data per-entry and merge on request - sort($options); - sort($entries); - $cache_key = 'mailboxes.metadata.' . $folder; - $cache_key .= '.' . md5(serialize($options).serialize($entries)); + if (!$force) { + // create cache key + // @TODO: this is the simplest solution, but we do the same with folders list + // maybe we should store data per-entry and merge on request + sort($options); + sort($entries); + $cache_key = 'mailboxes.metadata.' . $folder; + $cache_key .= '.' . md5(serialize($options).serialize($entries)); - // get cached data - $cached_data = $this->get_cache($cache_key); + // get cached data + $cached_data = $this->get_cache($cache_key); - if (is_array($cached_data)) { - return $cached_data; + if (is_array($cached_data)) { + return $cached_data; + } } if (!$this->check_connection()) { @@ -3829,20 +3939,28 @@ // @TODO: Honor MAXSIZE and DEPTH options foreach ($queries as $attrib => $entry) { - if ($result = $this->conn->getAnnotation($folder, $entry, $attrib)) { - $res = array_merge_recursive($res, $result); + $result = $this->conn->getAnnotation($folder, $entry, $attrib); + + // an error, invalidate any previous getAnnotation() results + if (!is_array($result)) { + return null; + } + else { + foreach ($result as $fldr => $data) { + $res[$fldr] = array_merge((array) $res[$fldr], $data); + } } } } if (isset($res)) { - $this->update_cache($cache_key, $res); + if (!$force) { + $this->update_cache($cache_key, $res); + } + return $res; } - - return null; } - /** * Converts the METADATA extension entry name into the correct @@ -3862,7 +3980,6 @@ } // @TODO: log error - return null; } @@ -3973,7 +4090,6 @@ } } - /** * Getter for messages cache object */ @@ -3992,7 +4108,6 @@ return $this->mcache; } - /** * Clears the messages cache. * @@ -4005,7 +4120,6 @@ $mcache->clear($folder, $uids); } } - /** * Delete outdated cache entries @@ -4036,7 +4150,6 @@ } } - /** * Sort folders first by default folders and then in alphabethical order * @@ -4047,67 +4160,85 @@ */ public function sort_folder_list($a_folders, $skip_default = false) { - $a_out = $a_defaults = $folders = array(); - - $delimiter = $this->get_hierarchy_delimiter(); $specials = array_merge(array('INBOX'), array_values($this->get_special_folders())); + $folders = array(); - // find default folders and skip folders starting with '.' + // convert names to UTF-8 foreach ($a_folders as $folder) { - if ($folder[0] == '.') { - continue; - } - - if (!$skip_default && ($p = array_search($folder, $specials)) !== false && !$a_defaults[$p]) { - $a_defaults[$p] = $folder; - } - else { - $folders[$folder] = rcube_charset::convert($folder, 'UTF7-IMAP'); - } + // for better performance skip encoding conversion + // if the string does not look like UTF7-IMAP + $folders[$folder] = strpos($folder, '&') === false ? $folder : rcube_charset::convert($folder, 'UTF7-IMAP'); } - // sort folders and place defaults on the top - asort($folders, SORT_LOCALE_STRING); - ksort($a_defaults); - $folders = array_merge($a_defaults, array_keys($folders)); + // sort folders + // asort($folders, SORT_LOCALE_STRING) is not properly sorting case sensitive names + uasort($folders, array($this, 'sort_folder_comparator')); - // finally we must rebuild the list to move - // subfolders of default folders to their place... - // ...also do this for the rest of folders because - // asort() is not properly sorting case sensitive names - while (list($key, $folder) = each($folders)) { - // set the type of folder name variable (#1485527) - $a_out[] = (string) $folder; - unset($folders[$key]); - $this->rsort($folder, $delimiter, $folders, $a_out); + $folders = array_keys($folders); + + if ($skip_default) { + return $folders; } - return $a_out; + // force the type of folder name variable (#1485527) + $folders = array_map('strval', $folders); + $out = array(); + + // finally we must put special folders on top and rebuild the list + // to move their subfolders where they belong... + $specials = array_unique(array_intersect($specials, $folders)); + $folders = array_merge($specials, array_diff($folders, $specials)); + + $this->sort_folder_specials(null, $folders, $specials, $out); + + return $out; } - /** - * Recursive method for sorting folders + * Recursive function to put subfolders of special folders in place */ - protected function rsort($folder, $delimiter, &$list, &$out) + protected function sort_folder_specials($folder, &$list, &$specials, &$out) { while (list($key, $name) = each($list)) { - if (strpos($name, $folder.$delimiter) === 0) { - // set the type of folder name variable (#1485527) - $out[] = (string) $name; + if ($folder === null || strpos($name, $folder.$this->delimiter) === 0) { + $out[] = $name; unset($list[$key]); - $this->rsort($name, $delimiter, $list, $out); + + if (!empty($specials) && ($found = array_search($name, $specials)) !== false) { + unset($specials[$found]); + $this->sort_folder_specials($name, $list, $specials, $out); + } } } + reset($list); } + /** + * Callback for uasort() that implements correct + * locale-aware case-sensitive sorting + */ + protected function sort_folder_comparator($str1, $str2) + { + $path1 = explode($this->delimiter, $str1); + $path2 = explode($this->delimiter, $str2); + + foreach ($path1 as $idx => $folder1) { + $folder2 = $path2[$idx]; + + if ($folder1 === $folder2) { + continue; + } + + return strcoll($folder1, $folder2); + } + } /** * Find UID of the specified message sequence ID * - * @param int $id Message (sequence) ID - * @param string $folder Folder name + * @param int $id Message (sequence) ID + * @param string $folder Folder name * * @return int Message UID */ @@ -4117,43 +4248,28 @@ $folder = $this->folder; } - if ($uid = array_search($id, (array)$this->uid_id_map[$folder])) { - return $uid; - } - if (!$this->check_connection()) { return null; } - $uid = $this->conn->ID2UID($folder, $id); - - $this->uid_id_map[$folder][$uid] = $id; - - return $uid; + return $this->conn->ID2UID($folder, $id); } - /** * Subscribe/unsubscribe a list of folders and update local cache */ protected function change_subscription($folders, $mode) { - $updated = false; + $updated = 0; + $folders = (array) $folders; if (!empty($folders)) { if (!$this->check_connection()) { return false; } - foreach ((array)$folders as $i => $folder) { - $folders[$i] = $folder; - - if ($mode == 'subscribe') { - $updated = $this->conn->subscribe($folder); - } - else if ($mode == 'unsubscribe') { - $updated = $this->conn->unsubscribe($folder); - } + foreach ($folders as $folder) { + $updated += (int) $this->conn->{$mode}($folder); } } @@ -4162,9 +4278,8 @@ $this->clear_cache('mailboxes', true); } - return $updated; + return $updated == count($folders) ? true : false; } - /** * Increde/decrese messagecount for a specific folder @@ -4196,7 +4311,6 @@ return true; } - /** * Remove messagecount of a specific folder from cache */ @@ -4214,7 +4328,6 @@ $this->update_cache('messagecount', $a_folder_cache); } } - /** * Converts date string/object into IMAP date/time format @@ -4238,159 +4351,11 @@ return $date->format('d-M-Y H:i:s O'); } - /** * This is our own debug handler for the IMAP connection - * @access public */ public function debug_handler(&$imap, $message) { rcube::write_log('imap', $message); } - - - /** - * Deprecated methods (to be removed) - */ - - public function decode_address_list($input, $max = null, $decode = true, $fallback = null) - { - return rcube_mime::decode_address_list($input, $max, $decode, $fallback); - } - - public function decode_header($input, $fallback = null) - { - return rcube_mime::decode_mime_string((string)$input, $fallback); - } - - public static function decode_mime_string($input, $fallback = null) - { - return rcube_mime::decode_mime_string($input, $fallback); - } - - public function mime_decode($input, $encoding = '7bit') - { - return rcube_mime::decode($input, $encoding); - } - - public static function explode_header_string($separator, $str, $remove_comments = false) - { - return rcube_mime::explode_header_string($separator, $str, $remove_comments); - } - - public function select_mailbox($mailbox) - { - // do nothing - } - - public function set_mailbox($folder) - { - $this->set_folder($folder); - } - - public function get_mailbox_name() - { - return $this->get_folder(); - } - - public function list_headers($folder='', $page=NULL, $sort_field=NULL, $sort_order=NULL, $slice=0) - { - return $this->list_messages($folder, $page, $sort_field, $sort_order, $slice); - } - - public function get_headers($uid, $folder = null, $force = false) - { - return $this->get_message_headers($uid, $folder, $force); - } - - public function mailbox_status($folder = null) - { - return $this->folder_status($folder); - } - - public function message_index($folder = '', $sort_field = NULL, $sort_order = NULL) - { - return $this->index($folder, $sort_field, $sort_order); - } - - public function message_index_direct($folder, $sort_field = null, $sort_order = null) - { - return $this->index_direct($folder, $sort_field, $sort_order); - } - - public function list_mailboxes($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) - { - return $this->list_folders_subscribed($root, $name, $filter, $rights, $skip_sort); - } - - public function list_unsubscribed($root='', $name='*', $filter=null, $rights=null, $skip_sort=false) - { - return $this->list_folders($root, $name, $filter, $rights, $skip_sort); - } - - public function get_mailbox_size($folder) - { - return $this->folder_size($folder); - } - - public function create_mailbox($folder, $subscribe=false) - { - return $this->create_folder($folder, $subscribe); - } - - public function rename_mailbox($folder, $new_name) - { - return $this->rename_folder($folder, $new_name); - } - - function delete_mailbox($folder) - { - return $this->delete_folder($folder); - } - - function clear_mailbox($folder = null) - { - return $this->clear_folder($folder); - } - - public function mailbox_exists($folder, $subscription=false) - { - return $this->folder_exists($folder, $subscription); - } - - public function mailbox_namespace($folder) - { - return $this->folder_namespace($folder); - } - - public function mod_mailbox($folder, $mode = 'out') - { - return $this->mod_folder($folder, $mode); - } - - public function mailbox_attributes($folder, $force=false) - { - return $this->folder_attributes($folder, $force); - } - - public function mailbox_data($folder) - { - return $this->folder_data($folder); - } - - public function mailbox_info($folder) - { - return $this->folder_info($folder); - } - - public function mailbox_sync($folder) - { - return $this->folder_sync($folder); - } - - public function expunge($folder='', $clear_cache=true) - { - return $this->expunge_folder($folder, $clear_cache); - } - } -- Gitblit v1.9.1