Mercurial > hg > rc2
comparison program/lib/Roundcube/rcube_imap_search.php @ 0:4681f974d28b
vanilla 1.3.3 distro, I hope
| author | Charlie Root |
|---|---|
| date | Thu, 04 Jan 2018 15:52:31 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:4681f974d28b |
|---|---|
| 1 <?php | |
| 2 | |
| 3 /** | |
| 4 +-----------------------------------------------------------------------+ | |
| 5 | This file is part of the Roundcube Webmail client | | |
| 6 | | | |
| 7 | Copyright (C) 2013, The Roundcube Dev Team | | |
| 8 | Copyright (C) 2014, Kolab Systems AG | | |
| 9 | | | |
| 10 | Licensed under the GNU General Public License version 3 or | | |
| 11 | any later version with exceptions for skins & plugins. | | |
| 12 | See the README file for a full license statement. | | |
| 13 | | | |
| 14 | PURPOSE: | | |
| 15 | Execute (multi-threaded) searches in multiple IMAP folders | | |
| 16 +-----------------------------------------------------------------------+ | |
| 17 | Author: Thomas Bruederli <roundcube@gmail.com> | | |
| 18 +-----------------------------------------------------------------------+ | |
| 19 */ | |
| 20 | |
| 21 /** | |
| 22 * Class to control search jobs on multiple IMAP folders. | |
| 23 * | |
| 24 * @package Framework | |
| 25 * @subpackage Storage | |
| 26 * @author Thomas Bruederli <roundcube@gmail.com> | |
| 27 */ | |
| 28 class rcube_imap_search | |
| 29 { | |
| 30 public $options = array(); | |
| 31 | |
| 32 protected $jobs = array(); | |
| 33 protected $timelimit = 0; | |
| 34 protected $results; | |
| 35 protected $conn; | |
| 36 | |
| 37 /** | |
| 38 * Default constructor | |
| 39 */ | |
| 40 public function __construct($options, $conn) | |
| 41 { | |
| 42 $this->options = $options; | |
| 43 $this->conn = $conn; | |
| 44 } | |
| 45 | |
| 46 /** | |
| 47 * Invoke search request to IMAP server | |
| 48 * | |
| 49 * @param array $folders List of IMAP folders to search in | |
| 50 * @param string $str Search criteria | |
| 51 * @param string $charset Search charset | |
| 52 * @param string $sort_field Header field to sort by | |
| 53 * @param boolean $threading True if threaded listing is active | |
| 54 */ | |
| 55 public function exec($folders, $str, $charset = null, $sort_field = null, $threading=null) | |
| 56 { | |
| 57 $start = floor(microtime(true)); | |
| 58 $results = new rcube_result_multifolder($folders); | |
| 59 | |
| 60 // start a search job for every folder to search in | |
| 61 foreach ($folders as $folder) { | |
| 62 // a complete result for this folder already exists | |
| 63 $result = $this->results ? $this->results->get_set($folder) : false; | |
| 64 if ($result && !$result->incomplete) { | |
| 65 $results->add($result); | |
| 66 } | |
| 67 else { | |
| 68 $search = is_array($str) && $str[$folder] ? $str[$folder] : $str; | |
| 69 $job = new rcube_imap_search_job($folder, $search, $charset, $sort_field, $threading); | |
| 70 $job->worker = $this; | |
| 71 $this->jobs[] = $job; | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 // execute jobs and gather results | |
| 76 foreach ($this->jobs as $job) { | |
| 77 // only run search if within the configured time limit | |
| 78 // TODO: try to estimate the required time based on folder size and previous search performance | |
| 79 if (!$this->timelimit || floor(microtime(true)) - $start < $this->timelimit) { | |
| 80 $job->run(); | |
| 81 } | |
| 82 | |
| 83 // add result (may have ->incomplete flag set) | |
| 84 $results->add($job->get_result()); | |
| 85 } | |
| 86 | |
| 87 return $results; | |
| 88 } | |
| 89 | |
| 90 /** | |
| 91 * Setter for timelimt property | |
| 92 */ | |
| 93 public function set_timelimit($seconds) | |
| 94 { | |
| 95 $this->timelimit = $seconds; | |
| 96 } | |
| 97 | |
| 98 /** | |
| 99 * Setter for previous (potentially incomplete) search results | |
| 100 */ | |
| 101 public function set_results($res) | |
| 102 { | |
| 103 $this->results = $res; | |
| 104 } | |
| 105 | |
| 106 /** | |
| 107 * Get connection to the IMAP server | |
| 108 * (used for single-thread mode) | |
| 109 */ | |
| 110 public function get_imap() | |
| 111 { | |
| 112 return $this->conn; | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 | |
| 117 /** | |
| 118 * Stackable item to run the search on a specific IMAP folder | |
| 119 */ | |
| 120 class rcube_imap_search_job /* extends Stackable */ | |
| 121 { | |
| 122 private $folder; | |
| 123 private $search; | |
| 124 private $charset; | |
| 125 private $sort_field; | |
| 126 private $threading; | |
| 127 private $result; | |
| 128 | |
| 129 public function __construct($folder, $str, $charset = null, $sort_field = null, $threading=false) | |
| 130 { | |
| 131 $this->folder = $folder; | |
| 132 $this->search = $str; | |
| 133 $this->charset = $charset; | |
| 134 $this->sort_field = $sort_field; | |
| 135 $this->threading = $threading; | |
| 136 | |
| 137 $this->result = new rcube_result_index($folder); | |
| 138 $this->result->incomplete = true; | |
| 139 } | |
| 140 | |
| 141 public function run() | |
| 142 { | |
| 143 $this->result = $this->search_index(); | |
| 144 } | |
| 145 | |
| 146 /** | |
| 147 * Copy of rcube_imap::search_index() | |
| 148 */ | |
| 149 protected function search_index() | |
| 150 { | |
| 151 $criteria = $this->search; | |
| 152 $charset = $this->charset; | |
| 153 $imap = $this->worker->get_imap(); | |
| 154 | |
| 155 if (!$imap->connected()) { | |
| 156 trigger_error("No IMAP connection for $this->folder", E_USER_WARNING); | |
| 157 | |
| 158 if ($this->threading) { | |
| 159 return new rcube_result_thread($this->folder); | |
| 160 } | |
| 161 else { | |
| 162 return new rcube_result_index($this->folder); | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 if ($this->worker->options['skip_deleted'] && !preg_match('/UNDELETED/', $criteria)) { | |
| 167 $criteria = 'UNDELETED '.$criteria; | |
| 168 } | |
| 169 | |
| 170 // unset CHARSET if criteria string is ASCII, this way | |
| 171 // SEARCH won't be re-sent after "unsupported charset" response | |
| 172 if ($charset && $charset != 'US-ASCII' && is_ascii($criteria)) { | |
| 173 $charset = 'US-ASCII'; | |
| 174 } | |
| 175 | |
| 176 if ($this->threading) { | |
| 177 $threads = $imap->thread($this->folder, $this->threading, $criteria, true, $charset); | |
| 178 | |
| 179 // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8, | |
| 180 // but I've seen that Courier doesn't support UTF-8) | |
| 181 if ($threads->is_error() && $charset && $charset != 'US-ASCII') { | |
| 182 $threads = $imap->thread($this->folder, $this->threading, | |
| 183 rcube_imap::convert_criteria($criteria, $charset), true, 'US-ASCII'); | |
| 184 } | |
| 185 | |
| 186 return $threads; | |
| 187 } | |
| 188 | |
| 189 if ($this->sort_field) { | |
| 190 $messages = $imap->sort($this->folder, $this->sort_field, $criteria, true, $charset); | |
| 191 | |
| 192 // Error, try with US-ASCII (RFC5256: SORT/THREAD must support US-ASCII and UTF-8, | |
| 193 // but I've seen Courier with disabled UTF-8 support) | |
| 194 if ($messages->is_error() && $charset && $charset != 'US-ASCII') { | |
| 195 $messages = $imap->sort($this->folder, $this->sort_field, | |
| 196 rcube_imap::convert_criteria($criteria, $charset), true, 'US-ASCII'); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 if (!$messages || $messages->is_error()) { | |
| 201 $messages = $imap->search($this->folder, | |
| 202 ($charset && $charset != 'US-ASCII' ? "CHARSET $charset " : '') . $criteria, true); | |
| 203 | |
| 204 // Error, try with US-ASCII (some servers may support only US-ASCII) | |
| 205 if ($messages->is_error() && $charset && $charset != 'US-ASCII') { | |
| 206 $messages = $imap->search($this->folder, | |
| 207 rcube_imap::convert_criteria($criteria, $charset), true); | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 return $messages; | |
| 212 } | |
| 213 | |
| 214 public function get_search_set() | |
| 215 { | |
| 216 return array( | |
| 217 $this->search, | |
| 218 $this->result, | |
| 219 $this->charset, | |
| 220 $this->sort_field, | |
| 221 $this->threading, | |
| 222 ); | |
| 223 } | |
| 224 | |
| 225 public function get_result() | |
| 226 { | |
| 227 return $this->result; | |
| 228 } | |
| 229 } |
