From c21f95f626e66b052309103e74d445300f68bdab Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Fri, 31 Jul 2015 05:20:50 -0400 Subject: [PATCH] Fix bug where new messages weren't added to the list in search mode --- program/lib/Roundcube/rcube_imap.php | 270 ++++++++++++++++++----------------------------------- 1 files changed, 92 insertions(+), 178 deletions(-) diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index a1fd874..9a4843d 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 | @@ -95,7 +95,6 @@ } } - /** * Magic getter for backward compat. * @@ -107,7 +106,6 @@ return $this->{$name}; } } - /** * Connect to an IMAP server @@ -203,7 +201,6 @@ return false; } - /** * Close IMAP connection. * Usually done on script shutdown @@ -215,7 +212,6 @@ $this->mcache->close(); } } - /** * Check connection state, connect if not connected. @@ -238,7 +234,6 @@ return $this->is_connected(); } - /** * Checks IMAP connection. * @@ -248,7 +243,6 @@ { return $this->conn->connected(); } - /** * Returns code of last error @@ -260,7 +254,6 @@ return $this->conn->errornum; } - /** * Returns text of last error * @@ -270,7 +263,6 @@ { return $this->conn->error; } - /** * Returns code of last command response @@ -301,7 +293,6 @@ } } - /** * Activate/deactivate debug mode * @@ -313,23 +304,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 @@ -352,7 +341,6 @@ } } - /** * Return the saved search set as hash array * @@ -372,7 +360,6 @@ $this->search_sorted, ); } - /** * Returns the IMAP server's capability. @@ -397,14 +384,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) { @@ -415,11 +401,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 */ @@ -447,25 +432,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) { @@ -478,7 +460,6 @@ unset($ns['prefix']); return $ns; } - /** * Sets delimiter and namespaces @@ -560,7 +541,6 @@ $_SESSION['imap_delimiter'] = $this->delimiter; } - /** * Get message count for a specific folder * @@ -570,7 +550,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) { @@ -581,29 +561,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(); } } @@ -696,7 +678,6 @@ return (int)$count; } - /** * Public method for listing message flags * @@ -731,7 +712,6 @@ return $result; } - /** * Public method for listing headers * @@ -741,7 +721,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) { @@ -752,7 +732,6 @@ return $this->_list_messages($folder, $page, $sort_field, $sort_order, $slice); } - /** * protected method for listing message headers * @@ -762,8 +741,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) { @@ -806,16 +785,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) { @@ -833,7 +811,7 @@ /** * Method for fetching threads data * - * @param string $folder Folder name + * @param string $folder Folder name * * @return rcube_imap_thread Thread data object */ @@ -857,11 +835,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 */ @@ -876,7 +853,6 @@ $this->options['skip_deleted'] ? 'UNDELETED' : '', true); } - /** * protected method for fetching threaded messages headers * @@ -885,7 +861,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) { @@ -915,13 +891,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 */ @@ -947,7 +922,6 @@ } } - /** * protected method for listing a set of message headers (search results) * @@ -955,7 +929,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) { @@ -1140,7 +1114,6 @@ } } - /** * protected method for listing a set of threaded message headers (search results) * @@ -1148,7 +1121,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) @@ -1163,7 +1136,6 @@ return $this->fetch_thread_headers($folder, clone $this->search_set, $page, $slice); } - /** * Fetches messages headers (by UID) @@ -1212,7 +1184,6 @@ return $a_msg_headers; } - /** * Returns current status of a folder (compared to the last time use) * @@ -1232,7 +1203,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; @@ -1260,7 +1231,6 @@ return $result; } - /** * Stores folder statistic data in session * @TODO: move to separate DB table (cache?) @@ -1273,7 +1243,6 @@ { $_SESSION['folders'][$folder][$name] = $data; } - /** * Gets folder statistic data @@ -1290,7 +1259,6 @@ return array(); } - /** * Return sorted list of message UIDs @@ -1369,7 +1337,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. @@ -1437,7 +1404,6 @@ return $index; } - /** * Return index of threaded message UIDs * @@ -1468,7 +1434,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. @@ -1497,7 +1462,6 @@ $threads->revert(); } } - /** * Invoke search request to IMAP server @@ -1574,7 +1538,6 @@ return $results; } - /** * Direct (real and simple) SEARCH request (without result sorting and caching). * @@ -1608,7 +1571,6 @@ return $index; } - /** * protected search method @@ -1686,7 +1648,6 @@ return $messages; } - /** * Converts charset of search criteria string * @@ -1726,7 +1687,6 @@ return $res; } - /** * Refresh saved search set * @@ -1758,7 +1718,6 @@ } } } - /** * Return message headers object of a specific message @@ -1798,13 +1757,12 @@ 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 */ @@ -1883,8 +1841,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 @@ -1924,7 +1882,6 @@ return $this->icache['message'] = $headers; } - /** * Build message part object * @@ -1932,7 +1889,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"; @@ -1957,6 +1914,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; } } @@ -2140,14 +2107,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']; @@ -2275,11 +2241,10 @@ } } - /** * Get charset name from message structure (first part) * - * @param array $structure Message structure + * @param array $structure Message structure * * @return string Charset name */ @@ -2308,7 +2273,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; @@ -2360,42 +2326,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 @@ -2411,7 +2376,6 @@ $this->conn->handlePartBody($this->folder, $uid, true, null, null, true, null, $formatted); } - /** * Set message flag to one or several messages @@ -2472,7 +2436,6 @@ return $result; } - /** * Append a mail message (source) to a specific folder * @@ -2529,7 +2492,6 @@ return $saved; } - /** * Move a message from one folder to another @@ -2608,7 +2570,6 @@ return $moved; } - /** * Copy a message from one folder to another * @@ -2644,7 +2605,6 @@ return $copied; } - /** * Mark messages as deleted and expunge them @@ -2702,7 +2662,6 @@ return $deleted; } - /** * Send IMAP expunge command and clear cache @@ -2826,15 +2785,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='*') { @@ -2871,7 +2829,7 @@ if (is_array($a_folders) && $name == '*' && !empty($this->conn->data['LIST'])) { foreach ($a_folders 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]); @@ -2894,7 +2852,6 @@ return $a_folders; } - /** * Get a list of all folders available on the server @@ -2964,15 +2921,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='*') { @@ -2996,13 +2952,12 @@ 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) */ protected function list_folders_update(&$result, $type = null) { @@ -3052,7 +3007,6 @@ } } - /** * Filter the given list of folders according to access rights * @@ -3078,7 +3032,6 @@ return $a_folders; } - /** * Get mailbox quota information * @@ -3094,7 +3047,6 @@ return false; } - /** * Get folder size (size of all messages in a folder) @@ -3119,7 +3071,6 @@ return $result; } - /** * Subscribe to a specific folder(s) * @@ -3133,7 +3084,6 @@ return $this->change_subscription($folders, 'subscribe'); } - /** * Unsubscribe folder(s) * @@ -3146,7 +3096,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 @@ -3165,16 +3114,6 @@ $result = $this->conn->createFolder($folder, $type ? array("\\" . ucfirst($type)) : null); - // it's quite often situation that we're trying to create and subscribe - // a folder that already exist, but is unsubscribed - if (!$result) { - if ($this->get_response_code() == rcube_storage::ALREADYEXISTS - || preg_match('/already exists/i', $this->get_error_str()) - ) { - $result = true; - } - } - // try to subscribe it if ($result) { // clear cache @@ -3187,7 +3126,6 @@ return $result; } - /** * Set a new name to an existing folder @@ -3248,7 +3186,6 @@ return $result; } - /** * Remove folder from server * @@ -3296,7 +3233,6 @@ return $result; } - /** * Detect special folder associations stored in storage backend */ @@ -3341,7 +3277,6 @@ return array_merge($result, $special); } - /** * Set special folder associations stored in storage backend */ @@ -3380,7 +3315,6 @@ return true; } - /** * Checks if folder exists and is subscribed * @@ -3408,7 +3342,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); } @@ -3433,7 +3367,6 @@ return false; } - /** * Returns the namespace where the folder is in @@ -3464,7 +3397,6 @@ return 'personal'; } - /** * Modify folder name according to namespace. @@ -3504,7 +3436,6 @@ return $folder; } - /** * Gets folder attributes from LIST response, e.g. \Noselect, \Noinferiors * @@ -3536,7 +3467,6 @@ return is_array($opts) ? $opts : array(); } - /** * Gets connection (and current folder) data: UIDVALIDITY, EXISTS, RECENT, @@ -3576,7 +3506,6 @@ return $data; } - /** * Returns extended information about the folder @@ -3673,7 +3602,6 @@ return $options; } - /** * Synchronizes messages cache. * @@ -3685,7 +3613,6 @@ $mcache->synchronize($folder); } } - /** * Get message header names for rcube_imap_generic::fetchHeader(s) @@ -3738,7 +3665,6 @@ return $this->conn->setACL($folder, $user, $acl); } - /** * Removes any <identifier,rights> pair for the * specified user from the ACL for the specified @@ -3763,7 +3689,6 @@ return $this->conn->deleteACL($folder, $user); } - /** * Returns the access control list for folder (GETACL) * @@ -3784,7 +3709,6 @@ return $this->conn->getACL($folder); } - /** * Returns information about what rights can be granted to the @@ -3809,7 +3733,6 @@ return $this->conn->listRights($folder, $user); } - /** * Returns the set of rights that the current user has to * folder (MYRIGHTS) @@ -3831,7 +3754,6 @@ return $this->conn->myRights($folder); } - /** * Sets IMAP metadata/annotations (SETMETADATA/SETANNOTATION) @@ -3866,7 +3788,6 @@ return false; } - /** * Unsets IMAP metadata/annotations (SETMETADATA/SETANNOTATION) * @@ -3899,7 +3820,6 @@ return false; } - /** * Returns IMAP metadata/annotations (GETMETADATA/GETANNOTATION) @@ -3951,7 +3871,13 @@ // @TODO: Honor MAXSIZE and DEPTH options foreach ($queries as $attrib => $entry) { - if ($result = $this->conn->getAnnotation($folder, $entry, $attrib)) { + $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); } @@ -3966,7 +3892,6 @@ return null; } - /** * Converts the METADATA extension entry name into the correct @@ -4097,7 +4022,6 @@ } } - /** * Getter for messages cache object */ @@ -4116,7 +4040,6 @@ return $this->mcache; } - /** * Clears the messages cache. * @@ -4129,7 +4052,6 @@ $mcache->clear($folder, $uids); } } - /** * Delete outdated cache entries @@ -4159,7 +4081,6 @@ $this->sort_order = strtoupper($sort_order) == 'DESC' ? 'DESC' : 'ASC'; } } - /** * Sort folders first by default folders and then in alphabethical order @@ -4247,12 +4168,11 @@ } } - /** * 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 */ @@ -4276,7 +4196,6 @@ return $uid; } - /** * Subscribe/unsubscribe a list of folders and update local cache @@ -4310,7 +4229,6 @@ return $updated; } - /** * Increde/decrese messagecount for a specific folder */ @@ -4341,7 +4259,6 @@ return true; } - /** * Remove messagecount of a specific folder from cache */ @@ -4359,7 +4276,6 @@ $this->update_cache('messagecount', $a_folder_cache); } } - /** * Converts date string/object into IMAP date/time format @@ -4382,7 +4298,6 @@ return $date->format('d-M-Y H:i:s O'); } - /** * This is our own debug handler for the IMAP connection @@ -4513,7 +4428,7 @@ return $this->mod_folder($folder, $mode); } - public function mailbox_attributes($folder, $force=false) + public function mailbox_attributes($folder, $force = false) { return $this->folder_attributes($folder, $force); } @@ -4533,9 +4448,8 @@ return $this->folder_sync($folder); } - public function expunge($folder='', $clear_cache=true) + public function expunge($folder = '', $clear_cache = true) { return $this->expunge_folder($folder, $clear_cache); } - } -- Gitblit v1.9.1