Aleksander Machniak
2016-05-16 0b7e26c1bf6bc7a684eb3a214d92d3927306cd8a
commit | author | age
566747 1 <?php
T 2
a95874 3 /**
566747 4  +-----------------------------------------------------------------------+
T 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 {
47a783 29     public $multi      = true;
AM 30     public $sets       = array();
31aa08 31     public $incomplete = false;
2c33c7 32     public $folder;
566747 33
47a783 34     protected $meta    = array();
AM 35     protected $index   = array();
e8cb51 36     protected $folders = array();
fef853 37     protected $sdata   = array();
47a783 38     protected $order   = 'ASC';
2c33c7 39     protected $sorting;
566747 40
T 41
42     /**
43      * Object constructor.
44      */
e8cb51 45     public function __construct($folders = array())
566747 46     {
e8cb51 47         $this->folders = $folders;
47a783 48         $this->meta    = array('count' => 0);
566747 49     }
T 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
6f9bb1 60         if ($result->count()) {
TB 61             $this->append_result($result);
31aa08 62         }
TB 63         else if ($result->incomplete) {
64             $this->incomplete = true;
689a22 65         }
6f9bb1 66     }
TB 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');
47a783 77         $index  = array_map(function($uid) use ($folder) { return $uid . '-' . $folder; }, $result->get());
AM 78
6f9bb1 79         $this->index = array_merge($this->index, $index);
566747 80     }
T 81
2c33c7 82     /**
TB 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;
47a783 93         $this->order   = $sort_order;
2c33c7 94     }
566747 95
T 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';
fef853 143         $this->index = array_reverse($this->index);
94e797 144
TB 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         }
566747 151     }
T 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     {
2c33c7 164         if (!empty($this->folder)) {
TB 165             $msgid .= '-' . $this->folder;
166         }
47a783 167
2c33c7 168         return array_search($msgid, $this->index);
566747 169     }
T 170
171     /**
172      * Filters data set. Removes elements listed in $ids list.
173      *
fef853 174      * @param array  $ids    List of IDs to remove.
566747 175      * @param string $folder IMAP folder
T 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             }
47a783 184
566747 185             $this->meta['count'] += $set->count();
T 186         }
187     }
188
189     /**
188304 190      * Slices data set.
TB 191      *
fef853 192      * @param int $offset Offset (as for PHP's array_slice())
AM 193      * @param int $length Number of elements (as for PHP's array_slice())
188304 194      */
TB 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     /**
566747 204      * Filters data set. Removes elements not listed in $ids list.
T 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     {
2c33c7 220         return $this->index;
566747 221     }
T 222
223     /**
fef853 224      * Return all messages in the result in compressed form
566747 225      *
fef853 226      * @return string List of message IDs in compressed form
566747 227      */
T 228     public function get_compressed()
229     {
230         return '';
231     }
232
233     /**
234      * Return result element at specified index
235      *
fef853 236      * @param int|string $index Element's index or "FIRST" or "LAST"
566747 237      *
T 238      * @return int Element value
239      */
2c33c7 240     public function get_element($idx)
566747 241     {
2c33c7 242         switch ($idx) {
TB 243             case 'FIRST': return $this->index[0];
244             case 'LAST':  return end($this->index);
245             default:      return $this->index[$idx];
246         }
566747 247     }
T 248
249     /**
250      * Returns response parameters, e.g. ESEARCH's MIN/MAX/COUNT/ALL/MODSEQ
251      * or internal data e.g. MAILBOX, ORDER
252      *
fef853 253      * @param string $param Parameter name
566747 254      *
T 255      * @return array|string Response parameters or parameter value
256      */
257     public function get_parameters($param=null)
258     {
2c33c7 259         $params = array(
47a783 260             'SORT'    => $this->sorting,
AM 261             'ORDER'   => $this->order,
e8cb51 262             'MAILBOX' => $this->folders,
2c33c7 263         );
TB 264
265         if ($param !== null) {
266             return $params[$param];
267         }
268
566747 269         return $params;
T 270     }
271
31aa08 272     /**
TB 273      * Returns the stored result object for a particular folder
274      *
fef853 275      * @param string $folder Folder name
AM 276      *
277      * @return false|object rcube_result_* instance of false if none found
31aa08 278      */
TB 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     }
566747 289
T 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     }
31aa08 299
TB 300
301     /* Serialize magic methods */
302
303     public function __sleep()
304     {
fef853 305         $this->sdata = array('incomplete' => array(), 'error' => array());
AM 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');
31aa08 317     }
TB 318
319     public function __wakeup()
320     {
fef853 321         $this->meta       = array('count' => count($this->index));
AM 322         $this->incomplete = count($this->sdata['incomplete']) > 0;
31aa08 323
fef853 324         // restore result sets from saved index
AM 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;
31aa08 334             }
fef853 335             else {
AM 336                 $data_str = '* SORT' . $data[$folder];
31aa08 337             }
fef853 338
AM 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;
31aa08 346         }
TB 347     }
566747 348 }