| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 | 
							- <?php
 - 
 - /**
 -  +-----------------------------------------------------------------------+
 -  | This file is part of the Roundcube Webmail client                     |
 -  | Copyright (C) 2005-2011, The Roundcube Dev Team                       |
 -  | Copyright (C) 2011, Kolab Systems AG                                  |
 -  |                                                                       |
 -  | Licensed under the GNU General Public License version 3 or            |
 -  | any later version with exceptions for skins & plugins.                |
 -  | See the README file for a full license statement.                     |
 -  |                                                                       |
 -  | PURPOSE:                                                              |
 -  |   SORT/SEARCH/ESEARCH response handler                                |
 -  +-----------------------------------------------------------------------+
 -  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
 -  | Author: Aleksander Machniak <alec@alec.pl>                            |
 -  +-----------------------------------------------------------------------+
 - */
 - 
 - /**
 -  * Class for accessing IMAP's SORT/SEARCH/ESEARCH result
 -  *
 -  * @package    Framework
 -  * @subpackage Storage
 -  */
 - class rcube_result_index
 - {
 -     public $incomplete = false;
 - 
 -     protected $raw_data;
 -     protected $mailbox;
 -     protected $meta   = array();
 -     protected $params = array();
 -     protected $order  = 'ASC';
 - 
 -     const SEPARATOR_ELEMENT = ' ';
 - 
 - 
 -     /**
 -      * Object constructor.
 -      */
 -     public function __construct($mailbox = null, $data = null, $order = null)
 -     {
 -         $this->mailbox = $mailbox;
 -         $this->order   = $order == 'DESC' ? 'DESC' : 'ASC';
 -         $this->init($data);
 -     }
 - 
 -     /**
 -      * Initializes object with SORT command response
 -      *
 -      * @param string $data IMAP response string
 -      */
 -     public function init($data = null)
 -     {
 -         $this->meta = array();
 - 
 -         $data = explode('*', (string)$data);
 - 
 -         // ...skip unilateral untagged server responses
 -         for ($i=0, $len=count($data); $i<$len; $i++) {
 -             $data_item = &$data[$i];
 -             if (preg_match('/^ SORT/i', $data_item)) {
 -                 // valid response, initialize raw_data for is_error()
 -                 $this->raw_data = '';
 -                 $data_item = substr($data_item, 5);
 -                 break;
 -             }
 -             else if (preg_match('/^ (E?SEARCH)/i', $data_item, $m)) {
 -                 // valid response, initialize raw_data for is_error()
 -                 $this->raw_data = '';
 -                 $data_item = substr($data_item, strlen($m[0]));
 - 
 -                 if (strtoupper($m[1]) == 'ESEARCH') {
 -                     $data_item = trim($data_item);
 -                     // remove MODSEQ response
 -                     if (preg_match('/\(MODSEQ ([0-9]+)\)$/i', $data_item, $m)) {
 -                         $data_item = substr($data_item, 0, -strlen($m[0]));
 -                         $this->params['MODSEQ'] = $m[1];
 -                     }
 -                     // remove TAG response part
 -                     if (preg_match('/^\(TAG ["a-z0-9]+\)\s*/i', $data_item, $m)) {
 -                         $data_item = substr($data_item, strlen($m[0]));
 -                     }
 -                     // remove UID
 -                     $data_item = preg_replace('/^UID\s*/i', '', $data_item);
 - 
 -                     // ESEARCH parameters
 -                     while (preg_match('/^([a-z]+) ([0-9:,]+)\s*/i', $data_item, $m)) {
 -                         $param = strtoupper($m[1]);
 -                         $value = $m[2];
 - 
 -                         $this->params[$param] = $value;
 -                         $data_item = substr($data_item, strlen($m[0]));
 - 
 -                         if (in_array($param, array('COUNT', 'MIN', 'MAX'))) {
 -                             $this->meta[strtolower($param)] = (int) $value;
 -                         }
 -                     }
 - 
 - // @TODO: Implement compression using compressMessageSet() in __sleep() and __wakeup() ?
 - // @TODO: work with compressed result?!
 -                     if (isset($this->params['ALL'])) {
 -                         $data_item = implode(self::SEPARATOR_ELEMENT,
 -                             rcube_imap_generic::uncompressMessageSet($this->params['ALL']));
 -                     }
 -                 }
 - 
 -                 break;
 -             }
 - 
 -             unset($data[$i]);
 -         }
 - 
 -         $data = array_filter($data);
 - 
 -         if (empty($data)) {
 -             return;
 -         }
 - 
 -         $data = array_shift($data);
 -         $data = trim($data);
 -         $data = preg_replace('/[\r\n]/', '', $data);
 -         $data = preg_replace('/\s+/', ' ', $data);
 - 
 -         $this->raw_data = $data;
 -     }
 - 
 -     /**
 -      * Checks the result from IMAP command
 -      *
 -      * @return bool True if the result is an error, False otherwise
 -      */
 -     public function is_error()
 -     {
 -         return $this->raw_data === null;
 -     }
 - 
 -     /**
 -      * Checks if the result is empty
 -      *
 -      * @return bool True if the result is empty, False otherwise
 -      */
 -     public function is_empty()
 -     {
 -         return empty($this->raw_data);
 -     }
 - 
 -     /**
 -      * Returns number of elements in the result
 -      *
 -      * @return int Number of elements
 -      */
 -     public function count()
 -     {
 -         if ($this->meta['count'] !== null)
 -             return $this->meta['count'];
 - 
 -         if (empty($this->raw_data)) {
 -             $this->meta['count']  = 0;
 -             $this->meta['length'] = 0;
 -         }
 -         else {
 -             $this->meta['count'] = 1 + substr_count($this->raw_data, self::SEPARATOR_ELEMENT);
 -         }
 - 
 -         return $this->meta['count'];
 -     }
 - 
 -     /**
 -      * Returns number of elements in the result.
 -      * Alias for count() for compatibility with rcube_result_thread
 -      *
 -      * @return int Number of elements
 -      */
 -     public function count_messages()
 -     {
 -         return $this->count();
 -     }
 - 
 -     /**
 -      * Returns maximal message identifier in the result
 -      *
 -      * @return int Maximal message identifier
 -      */
 -     public function max()
 -     {
 -         if (!isset($this->meta['max'])) {
 -             $this->meta['max'] = (int) @max($this->get());
 -         }
 - 
 -         return $this->meta['max'];
 -     }
 - 
 -     /**
 -      * Returns minimal message identifier in the result
 -      *
 -      * @return int Minimal message identifier
 -      */
 -     public function min()
 -     {
 -         if (!isset($this->meta['min'])) {
 -             $this->meta['min'] = (int) @min($this->get());
 -         }
 - 
 -         return $this->meta['min'];
 -     }
 - 
 -     /**
 -      * Slices data set.
 -      *
 -      * @param $offset Offset (as for PHP's array_slice())
 -      * @param $length Number of elements (as for PHP's array_slice())
 -      */
 -     public function slice($offset, $length)
 -     {
 -         $data = $this->get();
 -         $data = array_slice($data, $offset, $length);
 - 
 -         $this->meta          = array();
 -         $this->meta['count'] = count($data);
 -         $this->raw_data      = implode(self::SEPARATOR_ELEMENT, $data);
 -     }
 - 
 -     /**
 -      * Filters data set. Removes elements not listed in $ids list.
 -      *
 -      * @param array $ids List of IDs to remove.
 -      */
 -     public function filter($ids = array())
 -     {
 -         $data = $this->get();
 -         $data = array_intersect($data, $ids);
 - 
 -         $this->meta          = array();
 -         $this->meta['count'] = count($data);
 -         $this->raw_data      = implode(self::SEPARATOR_ELEMENT, $data);
 -     }
 - 
 -     /**
 -      * Reverts order of elements in the result
 -      */
 -     public function revert()
 -     {
 -         $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC';
 - 
 -         if (empty($this->raw_data)) {
 -             return;
 -         }
 - 
 -         $data = $this->get();
 -         $data = array_reverse($data);
 -         $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data);
 - 
 -         $this->meta['pos'] = array();
 -     }
 - 
 -     /**
 -      * Check if the given message ID exists in the object
 -      *
 -      * @param int  $msgid     Message ID
 -      * @param bool $get_index When enabled element's index will be returned.
 -      *                        Elements are indexed starting with 0
 -      *
 -      * @return mixed False if message ID doesn't exist, True if exists or
 -      *               index of the element if $get_index=true
 -      */
 -     public function exists($msgid, $get_index = false)
 -     {
 -         if (empty($this->raw_data)) {
 -             return false;
 -         }
 - 
 -         $msgid = (int) $msgid;
 -         $begin = implode('|', array('^', preg_quote(self::SEPARATOR_ELEMENT, '/')));
 -         $end   = implode('|', array('$', preg_quote(self::SEPARATOR_ELEMENT, '/')));
 - 
 -         if (preg_match("/($begin)$msgid($end)/", $this->raw_data, $m,
 -             $get_index ? PREG_OFFSET_CAPTURE : null)
 -         ) {
 -             if ($get_index) {
 -                 $idx = 0;
 -                 if ($m[0][1]) {
 -                     $idx = 1 + substr_count($this->raw_data, self::SEPARATOR_ELEMENT, 0, $m[0][1]);
 -                 }
 -                 // cache position of this element, so we can use it in get_element()
 -                 $this->meta['pos'][$idx] = (int)$m[0][1];
 - 
 -                 return $idx;
 -             }
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     /**
 -      * Return all messages in the result.
 -      *
 -      * @return array List of message IDs
 -      */
 -     public function get()
 -     {
 -         if (empty($this->raw_data)) {
 -             return array();
 -         }
 - 
 -         return explode(self::SEPARATOR_ELEMENT, $this->raw_data);
 -     }
 - 
 -     /**
 -      * Return all messages in the result.
 -      *
 -      * @return array List of message IDs
 -      */
 -     public function get_compressed()
 -     {
 -         if (empty($this->raw_data)) {
 -             return '';
 -         }
 - 
 -         return rcube_imap_generic::compressMessageSet($this->get());
 -     }
 - 
 -     /**
 -      * Return result element at specified index
 -      *
 -      * @param int|string  $index  Element's index or "FIRST" or "LAST"
 -      *
 -      * @return int Element value
 -      */
 -     public function get_element($index)
 -     {
 -         $count = $this->count();
 - 
 -         if (!$count) {
 -             return null;
 -         }
 - 
 -         // first element
 -         if ($index === 0 || $index === '0' || $index === 'FIRST') {
 -             $pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT);
 -             if ($pos === false)
 -                 $result = (int) $this->raw_data;
 -             else
 -                 $result = (int) substr($this->raw_data, 0, $pos);
 - 
 -             return $result;
 -         }
 - 
 -         // last element
 -         if ($index === 'LAST' || $index == $count-1) {
 -             $pos = strrpos($this->raw_data, self::SEPARATOR_ELEMENT);
 -             if ($pos === false)
 -                 $result = (int) $this->raw_data;
 -             else
 -                 $result = (int) substr($this->raw_data, $pos);
 - 
 -             return $result;
 -         }
 - 
 -         // do we know the position of the element or the neighbour of it?
 -         if (!empty($this->meta['pos'])) {
 -             if (isset($this->meta['pos'][$index]))
 -                 $pos = $this->meta['pos'][$index];
 -             else if (isset($this->meta['pos'][$index-1]))
 -                 $pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT,
 -                     $this->meta['pos'][$index-1] + 1);
 -             else if (isset($this->meta['pos'][$index+1]))
 -                 $pos = strrpos($this->raw_data, self::SEPARATOR_ELEMENT,
 -                     $this->meta['pos'][$index+1] - $this->length() - 1);
 - 
 -             if (isset($pos) && preg_match('/([0-9]+)/', $this->raw_data, $m, null, $pos)) {
 -                 return (int) $m[1];
 -             }
 -         }
 - 
 -         // Finally use less effective method
 -         $data = explode(self::SEPARATOR_ELEMENT, $this->raw_data);
 - 
 -         return $data[$index];
 -     }
 - 
 -     /**
 -      * Returns response parameters, e.g. ESEARCH's MIN/MAX/COUNT/ALL/MODSEQ
 -      * or internal data e.g. MAILBOX, ORDER
 -      *
 -      * @param string $param  Parameter name
 -      *
 -      * @return array|string Response parameters or parameter value
 -      */
 -     public function get_parameters($param=null)
 -     {
 -         $params = $this->params;
 -         $params['MAILBOX'] = $this->mailbox;
 -         $params['ORDER']   = $this->order;
 - 
 -         if ($param !== null) {
 -             return $params[$param];
 -         }
 - 
 -         return $params;
 -     }
 - 
 -     /**
 -      * Returns length of internal data representation
 -      *
 -      * @return int Data length
 -      */
 -     protected function length()
 -     {
 -         if (!isset($this->meta['length'])) {
 -             $this->meta['length'] = strlen($this->raw_data);
 -         }
 - 
 -         return $this->meta['length'];
 -     }
 - }
 
 
  |