gXbfB#) ۻbis_IIߪ ۻbis_IIߪ ۻbis_IIߪ ۻbis_II4&D.5;Aϳކ:}Wۻp%7ޔ_#5LGZB骙!6 yC N/"Kn%JE)U[HB4bCCe+vN(x0n^ j pٯLa߽ _S NV&x_wo2b|zerpQ,6'+~^܉RT#:Ì0K- 3bó+%(XtRPo6X:A0)kVPՐQuv''Fk6٠(\zUd_=M` 3Ȍ5P>CoNzRY@Ze^6F=<4J"`2 1(+aTb?2y`z@6pIT} <= q/b'BI0x&P]dMZ[OBrYA^H(ЊH?9|F{Sflt0-g_7 rnsJL4xQX-eX! '@v縐[ă²Q'x]1}TM$ eucwƁoe(y<^;+W,Oiq7D>ޯ%hxA%fh31ؙ<^o~gob'\o΂S y',݌>)RWY`cOm,oПp+_XTAuV0& IOGc])ͣr/6\pmr^3UOV]oluqLPs(^ocu/ISuN°9''9Te w.? f'J3Qp#ǽʎ:𐃟Q3WxNHLwgFN5K]O-#\38%!P۟LqЫs%"R&k|$I exijxբ7]ZcFI@-dఐ#5x5/c8edl0F.\J)+iwgFN5K]O>0(w?rT)Z#sGQK0N`m7,杫gN$Z yY#,vۍXm^uK ݼd[q/ J{3&~!K mԘYc+XƵs'ʳ_;@wgFN5K]OCh Tф'IcDQ)!b{s9{ވ>ޯ%ٷ(ž'I#HkP:a0^O+P`>D+muʆ ߴ/#$aS?}T瘫1iM8e8wC|>01htIKQ6-Sp,B#aw1 t>>ޯ%߉RHQcCe,LА#]U 3f1Nrjf-(:c>6FQؾNM"wgFN5K]O`r-p*Fo޵%/k#wgFN5K]O:\\x)Oo_IЋI7[)4'}#Pcn)r^p;QS 9Wf4wgFN5K]O:u* 9_4mPSsy~v8q86VŻ4{l`zOMJ%e4^$ω겙ЫHW3H-Ci7f}nq R1 σ7u]??LwgFN5K]OPEwoy& # o="6Ģ4Ӗu냻V]>$Մw](wgFN5K]O 26r_'#iP1ii ߥ[.}!W7RH]7:-'$2ځOEt~2F\Cl fUa^G^;wS&{ %%u=i [d~M} Æ\vT7sed 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_first($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) && empty($this->meta['max']) && empty($this->meta['min']) && empty($this->meta['count']); } /** * Returns number of elements in the result * * @return int Number of elements */ public function count() { if (isset($this->meta['count'])) { 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|null Maximal message identifier */ public function max() { if ($this->is_empty()) { return null; } if (!isset($this->meta['max'])) { $this->meta['max'] = null; $all = $this->get(); if (!empty($all)) { $this->meta['max'] = (int) max($all); } } return $this->meta['max']; } /** * Returns minimal message identifier in the result * * @return int|null Minimal message identifier */ public function min() { if ($this->is_empty()) { return null; } if (!isset($this->meta['min'])) { $this->meta['min'] = null; $all = $this->get(); if (!empty($all)) { $this->meta['min'] = (int) min($all); } } return $this->meta['min']; } /** * Slices data set. * * @param int $offset Offset (as for PHP's array_slice()) * @param int $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 = []; $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 = []) { $data = $this->get(); $data = array_intersect($data, $ids); $this->meta = []; $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'] = []; } /** * 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('|', ['^', preg_quote(self::SEPARATOR_ELEMENT, '/')]); $end = implode('|', ['$', preg_quote(self::SEPARATOR_ELEMENT, '/')]); if (preg_match("/($begin)$msgid($end)/", $this->raw_data, $m, $get_index ? PREG_OFFSET_CAPTURE : 0) ) { if ($get_index) { $idx = 0; if (!empty($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 []; } 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|null Element value */ public function get_element($index) { if (empty($this->raw_data)) { return null; } $count = $this->count(); // 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, 0, $pos)) { return (int) $m[1]; } } // Finally use less effective method $data = explode(self::SEPARATOR_ELEMENT, $this->raw_data); return (int) $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] ?? null; } 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']; } }