0
|
1 <?php
|
|
2
|
|
3 /**
|
|
4 +-----------------------------------------------------------------------+
|
|
5 | This file is part of the Roundcube Webmail client |
|
|
6 | Copyright (C) 2005-2011, The Roundcube Dev Team |
|
|
7 | Copyright (C) 2011, Kolab Systems AG |
|
|
8 | |
|
|
9 | Licensed under the GNU General Public License version 3 or |
|
|
10 | any later version with exceptions for skins & plugins. |
|
|
11 | See the README file for a full license statement. |
|
|
12 | |
|
|
13 | PURPOSE: |
|
|
14 | SORT/SEARCH/ESEARCH response handler |
|
|
15 +-----------------------------------------------------------------------+
|
|
16 | Author: Thomas Bruederli <roundcube@gmail.com> |
|
|
17 +-----------------------------------------------------------------------+
|
|
18 */
|
|
19
|
|
20 /**
|
|
21 * Class holding a set of rcube_result_index instances that together form a
|
|
22 * result set of a multi-folder search
|
|
23 *
|
|
24 * @package Framework
|
|
25 * @subpackage Storage
|
|
26 */
|
|
27 class rcube_result_multifolder
|
|
28 {
|
|
29 public $multi = true;
|
|
30 public $sets = array();
|
|
31 public $incomplete = false;
|
|
32 public $folder;
|
|
33
|
|
34 protected $meta = array();
|
|
35 protected $index = array();
|
|
36 protected $folders = array();
|
|
37 protected $sdata = array();
|
|
38 protected $order = 'ASC';
|
|
39 protected $sorting;
|
|
40
|
|
41
|
|
42 /**
|
|
43 * Object constructor.
|
|
44 */
|
|
45 public function __construct($folders = array())
|
|
46 {
|
|
47 $this->folders = $folders;
|
|
48 $this->meta = array('count' => 0);
|
|
49 }
|
|
50
|
|
51 /**
|
|
52 * Initializes object with SORT command response
|
|
53 *
|
|
54 * @param string $data IMAP response string
|
|
55 */
|
|
56 public function add($result)
|
|
57 {
|
|
58 $this->sets[] = $result;
|
|
59
|
|
60 if ($result->count()) {
|
|
61 $this->append_result($result);
|
|
62 }
|
|
63 else if ($result->incomplete) {
|
|
64 $this->incomplete = true;
|
|
65 }
|
|
66 }
|
|
67
|
|
68 /**
|
|
69 * Append message UIDs from the given result to our index
|
|
70 */
|
|
71 protected function append_result($result)
|
|
72 {
|
|
73 $this->meta['count'] += $result->count();
|
|
74
|
|
75 // append UIDs to global index
|
|
76 $folder = $result->get_parameters('MAILBOX');
|
|
77 $index = array_map(function($uid) use ($folder) { return $uid . '-' . $folder; }, $result->get());
|
|
78
|
|
79 $this->index = array_merge($this->index, $index);
|
|
80 }
|
|
81
|
|
82 /**
|
|
83 * Store a global index of (sorted) message UIDs
|
|
84 */
|
|
85 public function set_message_index($headers, $sort_field, $sort_order)
|
|
86 {
|
|
87 $this->index = array();
|
|
88 foreach ($headers as $header) {
|
|
89 $this->index[] = $header->uid . '-' . $header->folder;
|
|
90 }
|
|
91
|
|
92 $this->sorting = $sort_field;
|
|
93 $this->order = $sort_order;
|
|
94 }
|
|
95
|
|
96 /**
|
|
97 * Checks the result from IMAP command
|
|
98 *
|
|
99 * @return bool True if the result is an error, False otherwise
|
|
100 */
|
|
101 public function is_error()
|
|
102 {
|
|
103 return false;
|
|
104 }
|
|
105
|
|
106 /**
|
|
107 * Checks if the result is empty
|
|
108 *
|
|
109 * @return bool True if the result is empty, False otherwise
|
|
110 */
|
|
111 public function is_empty()
|
|
112 {
|
|
113 return empty($this->sets) || $this->meta['count'] == 0;
|
|
114 }
|
|
115
|
|
116 /**
|
|
117 * Returns number of elements in the result
|
|
118 *
|
|
119 * @return int Number of elements
|
|
120 */
|
|
121 public function count()
|
|
122 {
|
|
123 return $this->meta['count'];
|
|
124 }
|
|
125
|
|
126 /**
|
|
127 * Returns number of elements in the result.
|
|
128 * Alias for count() for compatibility with rcube_result_thread
|
|
129 *
|
|
130 * @return int Number of elements
|
|
131 */
|
|
132 public function count_messages()
|
|
133 {
|
|
134 return $this->count();
|
|
135 }
|
|
136
|
|
137 /**
|
|
138 * Reverts order of elements in the result
|
|
139 */
|
|
140 public function revert()
|
|
141 {
|
|
142 $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC';
|
|
143 $this->index = array_reverse($this->index);
|
|
144
|
|
145 // revert order in all sub-sets
|
|
146 foreach ($this->sets as $set) {
|
|
147 if ($this->order != $set->get_parameters('ORDER')) {
|
|
148 $set->revert();
|
|
149 }
|
|
150 }
|
|
151 }
|
|
152
|
|
153 /**
|
|
154 * Check if the given message ID exists in the object
|
|
155 *
|
|
156 * @param int $msgid Message ID
|
|
157 * @param bool $get_index When enabled element's index will be returned.
|
|
158 * Elements are indexed starting with 0
|
|
159 * @return mixed False if message ID doesn't exist, True if exists or
|
|
160 * index of the element if $get_index=true
|
|
161 */
|
|
162 public function exists($msgid, $get_index = false)
|
|
163 {
|
|
164 if (!empty($this->folder)) {
|
|
165 $msgid .= '-' . $this->folder;
|
|
166 }
|
|
167
|
|
168 return array_search($msgid, $this->index);
|
|
169 }
|
|
170
|
|
171 /**
|
|
172 * Filters data set. Removes elements listed in $ids list.
|
|
173 *
|
|
174 * @param array $ids List of IDs to remove.
|
|
175 * @param string $folder IMAP folder
|
|
176 */
|
|
177 public function filter($ids = array(), $folder = null)
|
|
178 {
|
|
179 $this->meta['count'] = 0;
|
|
180 foreach ($this->sets as $set) {
|
|
181 if ($set->get_parameters('MAILBOX') == $folder) {
|
|
182 $set->filter($ids);
|
|
183 }
|
|
184
|
|
185 $this->meta['count'] += $set->count();
|
|
186 }
|
|
187 }
|
|
188
|
|
189 /**
|
|
190 * Slices data set.
|
|
191 *
|
|
192 * @param int $offset Offset (as for PHP's array_slice())
|
|
193 * @param int $length Number of elements (as for PHP's array_slice())
|
|
194 */
|
|
195 public function slice($offset, $length)
|
|
196 {
|
|
197 $data = array_slice($this->get(), $offset, $length);
|
|
198
|
|
199 $this->index = $data;
|
|
200 $this->meta['count'] = count($data);
|
|
201 }
|
|
202
|
|
203 /**
|
|
204 * Filters data set. Removes elements not listed in $ids list.
|
|
205 *
|
|
206 * @param array $ids List of IDs to keep.
|
|
207 */
|
|
208 public function intersect($ids = array())
|
|
209 {
|
|
210 // not implemented
|
|
211 }
|
|
212
|
|
213 /**
|
|
214 * Return all messages in the result.
|
|
215 *
|
|
216 * @return array List of message IDs
|
|
217 */
|
|
218 public function get()
|
|
219 {
|
|
220 return $this->index;
|
|
221 }
|
|
222
|
|
223 /**
|
|
224 * Return all messages in the result in compressed form
|
|
225 *
|
|
226 * @return string List of message IDs in compressed form
|
|
227 */
|
|
228 public function get_compressed()
|
|
229 {
|
|
230 return '';
|
|
231 }
|
|
232
|
|
233 /**
|
|
234 * Return result element at specified index
|
|
235 *
|
|
236 * @param int|string $index Element's index or "FIRST" or "LAST"
|
|
237 *
|
|
238 * @return int Element value
|
|
239 */
|
|
240 public function get_element($idx)
|
|
241 {
|
|
242 switch ($idx) {
|
|
243 case 'FIRST': return $this->index[0];
|
|
244 case 'LAST': return end($this->index);
|
|
245 default: return $this->index[$idx];
|
|
246 }
|
|
247 }
|
|
248
|
|
249 /**
|
|
250 * Returns response parameters, e.g. ESEARCH's MIN/MAX/COUNT/ALL/MODSEQ
|
|
251 * or internal data e.g. MAILBOX, ORDER
|
|
252 *
|
|
253 * @param string $param Parameter name
|
|
254 *
|
|
255 * @return array|string Response parameters or parameter value
|
|
256 */
|
|
257 public function get_parameters($param=null)
|
|
258 {
|
|
259 $params = array(
|
|
260 'SORT' => $this->sorting,
|
|
261 'ORDER' => $this->order,
|
|
262 'MAILBOX' => $this->folders,
|
|
263 );
|
|
264
|
|
265 if ($param !== null) {
|
|
266 return $params[$param];
|
|
267 }
|
|
268
|
|
269 return $params;
|
|
270 }
|
|
271
|
|
272 /**
|
|
273 * Returns the stored result object for a particular folder
|
|
274 *
|
|
275 * @param string $folder Folder name
|
|
276 *
|
|
277 * @return false|object rcube_result_* instance of false if none found
|
|
278 */
|
|
279 public function get_set($folder)
|
|
280 {
|
|
281 foreach ($this->sets as $set) {
|
|
282 if ($set->get_parameters('MAILBOX') == $folder) {
|
|
283 return $set;
|
|
284 }
|
|
285 }
|
|
286
|
|
287 return false;
|
|
288 }
|
|
289
|
|
290 /**
|
|
291 * Returns length of internal data representation
|
|
292 *
|
|
293 * @return int Data length
|
|
294 */
|
|
295 protected function length()
|
|
296 {
|
|
297 return $this->count();
|
|
298 }
|
|
299
|
|
300
|
|
301 /* Serialize magic methods */
|
|
302
|
|
303 public function __sleep()
|
|
304 {
|
|
305 $this->sdata = array('incomplete' => array(), 'error' => array());
|
|
306
|
|
307 foreach ($this->sets as $set) {
|
|
308 if ($set->incomplete) {
|
|
309 $this->sdata['incomplete'][] = $set->get_parameters('MAILBOX');
|
|
310 }
|
|
311 else if ($set->is_error()) {
|
|
312 $this->sdata['error'][] = $set->get_parameters('MAILBOX');
|
|
313 }
|
|
314 }
|
|
315
|
|
316 return array('sdata', 'index', 'folders', 'sorting', 'order');
|
|
317 }
|
|
318
|
|
319 public function __wakeup()
|
|
320 {
|
|
321 $this->meta = array('count' => count($this->index));
|
|
322 $this->incomplete = count($this->sdata['incomplete']) > 0;
|
|
323
|
|
324 // restore result sets from saved index
|
|
325 $data = array();
|
|
326 foreach ($this->index as $item) {
|
|
327 list($uid, $folder) = explode('-', $item, 2);
|
|
328 $data[$folder] .= ' ' . $uid;
|
|
329 }
|
|
330
|
|
331 foreach ($this->folders as $folder) {
|
|
332 if (in_array($folder, $this->sdata['error'])) {
|
|
333 $data_str = null;
|
|
334 }
|
|
335 else {
|
|
336 $data_str = '* SORT' . $data[$folder];
|
|
337 }
|
|
338
|
|
339 $set = new rcube_result_index($folder, $data_str, strtoupper($this->order));
|
|
340
|
|
341 if (in_array($folder, $this->sdata['incomplete'])) {
|
|
342 $set->incomplete = true;
|
|
343 }
|
|
344
|
|
345 $this->sets[] = $set;
|
|
346 }
|
|
347 }
|
|
348 }
|