Thomas Bruederli
2014-04-23 31aa080609f6ea8a561182eb5b3da46733bef313
commit | author | age
566747 1 <?php
T 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();
31aa08 31     public $incomplete = false;
2c33c7 32     public $folder;
566747 33
T 34     protected $meta = array();
2c33c7 35     protected $index = array();
e8cb51 36     protected $folders = array();
2c33c7 37     protected $sorting;
566747 38     protected $order = 'ASC';
T 39
40
41     /**
42      * Object constructor.
43      */
e8cb51 44     public function __construct($folders = array())
566747 45     {
e8cb51 46         $this->folders = $folders;
566747 47         $this->meta = array('count' => 0);
T 48     }
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     {
31aa08 58         $this->sets[] = $result;
TB 59
689a22 60         if ($count = $result->count()) {
TB 61             $this->meta['count'] += $count;
62
63             // append UIDs to global index
64             $folder = $result->get_parameters('MAILBOX');
65             $index = array_map(function($uid) use ($folder) { return $uid . '-' . $folder; }, $result->get());
66             $this->index = array_merge($this->index, $index);
31aa08 67         }
TB 68         else if ($result->incomplete) {
69             $this->incomplete = true;
689a22 70         }
566747 71     }
T 72
2c33c7 73     /**
TB 74      * Store a global index of (sorted) message UIDs
75      */
76     public function set_message_index($headers, $sort_field, $sort_order)
77     {
78         $this->index = array();
79         foreach ($headers as $header) {
80             $this->index[] = $header->uid . '-' . $header->folder;
81         }
82
83         $this->sorting = $sort_field;
84         $this->order = $sort_order;
85     }
566747 86
T 87     /**
88      * Checks the result from IMAP command
89      *
90      * @return bool True if the result is an error, False otherwise
91      */
92     public function is_error()
93     {
94         return false;
95     }
96
97
98     /**
99      * Checks if the result is empty
100      *
101      * @return bool True if the result is empty, False otherwise
102      */
103     public function is_empty()
104     {
105         return empty($this->sets) || $this->meta['count'] == 0;
106     }
107
108
109     /**
110      * Returns number of elements in the result
111      *
112      * @return int Number of elements
113      */
114     public function count()
115     {
116         return $this->meta['count'];
117     }
118
119
120     /**
121      * Returns number of elements in the result.
122      * Alias for count() for compatibility with rcube_result_thread
123      *
124      * @return int Number of elements
125      */
126     public function count_messages()
127     {
128         return $this->count();
129     }
130
131
132     /**
133      * Reverts order of elements in the result
134      */
135     public function revert()
136     {
137         $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC';
94e797 138         $this->index = array();
TB 139
140         // revert order in all sub-sets
141         foreach ($this->sets as $set) {
142             if ($this->order != $set->get_parameters('ORDER')) {
143                 $set->revert();
144             }
145             $folder = $set->get_parameters('MAILBOX');
146             $index = array_map(function($uid) use ($folder) { return $uid . '-' . $folder; }, $set->get());
147             $this->index = array_merge($this->index, $index);
148         }
566747 149     }
T 150
151
152     /**
153      * Check if the given message ID exists in the object
154      *
155      * @param int  $msgid     Message ID
156      * @param bool $get_index When enabled element's index will be returned.
157      *                        Elements are indexed starting with 0
158      * @return mixed False if message ID doesn't exist, True if exists or
159      *               index of the element if $get_index=true
160      */
161     public function exists($msgid, $get_index = false)
162     {
2c33c7 163         if (!empty($this->folder)) {
TB 164             $msgid .= '-' . $this->folder;
165         }
166         return array_search($msgid, $this->index);
566747 167     }
T 168
169
170     /**
171      * Filters data set. Removes elements listed in $ids list.
172      *
173      * @param array $ids List of IDs to remove.
174      * @param string $folder IMAP folder
175      */
176     public function filter($ids = array(), $folder = null)
177     {
178         $this->meta['count'] = 0;
179         foreach ($this->sets as $set) {
180             if ($set->get_parameters('MAILBOX') == $folder) {
181                 $set->filter($ids);
182             }
183             $this->meta['count'] += $set->count();
184         }
185     }
186
187     /**
188304 188      * Slices data set.
TB 189      *
190      * @param $offset Offset (as for PHP's array_slice())
191      * @param $length Number of elements (as for PHP's array_slice())
192      *
193      */
194     public function slice($offset, $length)
195     {
196         $data = array_slice($this->get(), $offset, $length);
197
198         $this->index = $data;
199         $this->meta['count'] = count($data);
200     }
201
202     /**
566747 203      * Filters data set. Removes elements not listed in $ids list.
T 204      *
205      * @param array $ids List of IDs to keep.
206      */
207     public function intersect($ids = array())
208     {
209         // not implemented
210     }
211
212     /**
213      * Return all messages in the result.
214      *
215      * @return array List of message IDs
216      */
217     public function get()
218     {
2c33c7 219         return $this->index;
566747 220     }
T 221
222
223     /**
224      * Return all messages in the result.
225      *
226      * @return array List of message IDs
227      */
228     public function get_compressed()
229     {
230         return '';
231     }
232
233
234     /**
235      * Return result element at specified index
236      *
237      * @param int|string  $index  Element's index or "FIRST" or "LAST"
238      *
239      * @return int Element value
240      */
2c33c7 241     public function get_element($idx)
566747 242     {
2c33c7 243         switch ($idx) {
TB 244             case 'FIRST': return $this->index[0];
245             case 'LAST':  return end($this->index);
246             default:      return $this->index[$idx];
247         }
566747 248     }
T 249
250
251     /**
252      * Returns response parameters, e.g. ESEARCH's MIN/MAX/COUNT/ALL/MODSEQ
253      * or internal data e.g. MAILBOX, ORDER
254      *
255      * @param string $param  Parameter name
256      *
257      * @return array|string Response parameters or parameter value
258      */
259     public function get_parameters($param=null)
260     {
2c33c7 261         $params = array(
TB 262             'SORT' => $this->sorting,
263             'ORDER' => $this->order,
e8cb51 264             'MAILBOX' => $this->folders,
2c33c7 265         );
TB 266
267         if ($param !== null) {
268             return $params[$param];
269         }
270
566747 271         return $params;
T 272     }
273
31aa08 274     /**
TB 275      * Returns the stored result object for a particular folder
276      *
277      * @param string $folder  Folder name
278      * @return false|obejct rcube_result_* instance of false if none found
279      */
280     public function get_set($folder)
281     {
282         foreach ($this->sets as $set) {
283             if ($set->get_parameters('MAILBOX') == $folder) {
284                 return $set;
285             }
286         }
287
288         return false;
289     }
566747 290
T 291     /**
292      * Returns length of internal data representation
293      *
294      * @return int Data length
295      */
296     protected function length()
297     {
298         return $this->count();
299     }
31aa08 300
TB 301
302     /* Serialize magic methods */
303
304     public function __sleep()
305     {
306         return array('sets','folders','sorting','order');
307     }
308
309     public function __wakeup()
310     {
311         // restore index from saved result sets
312         $this->meta = array('count' => 0);
313
314         foreach ($this->sets as $result) {
315             if ($count = $result->count()) {
316                 $this->meta['count'] += $count;
317
318                 // append UIDs to global index
319                 $folder = $result->get_parameters('MAILBOX');
320                 $index = array_map(function($uid) use ($folder) { return $uid . '-' . $folder; }, $result->get());
321                 $this->index = array_merge($this->index, $index);
322             }
323             else if ($result->incomplete) {
324                 $this->incomplete = true;
325             }
326         }
327     }
328
566747 329 }