Horde_Imap_Client_Socket::_search PHP Method

    protected function _search($query, $options)
    {
        $sort_criteria = array(Horde_Imap_Client::SORT_ARRIVAL => 'ARRIVAL', Horde_Imap_Client::SORT_CC => 'CC', Horde_Imap_Client::SORT_DATE => 'DATE', Horde_Imap_Client::SORT_DISPLAYFROM => 'DISPLAYFROM', Horde_Imap_Client::SORT_DISPLAYTO => 'DISPLAYTO', Horde_Imap_Client::SORT_FROM => 'FROM', Horde_Imap_Client::SORT_REVERSE => 'REVERSE', Horde_Imap_Client::SORT_RELEVANCY => 'RELEVANCY', Horde_Imap_Client::SORT_SEQUENCE => 'SEQUENCE', Horde_Imap_Client::SORT_SIZE => 'SIZE', Horde_Imap_Client::SORT_SUBJECT => 'SUBJECT', Horde_Imap_Client::SORT_TO => 'TO');
        $results_criteria = array(Horde_Imap_Client::SEARCH_RESULTS_COUNT => 'COUNT', Horde_Imap_Client::SEARCH_RESULTS_MATCH => 'ALL', Horde_Imap_Client::SEARCH_RESULTS_MAX => 'MAX', Horde_Imap_Client::SEARCH_RESULTS_MIN => 'MIN', Horde_Imap_Client::SEARCH_RESULTS_RELEVANCY => 'RELEVANCY', Horde_Imap_Client::SEARCH_RESULTS_SAVE => 'SAVE');
        // Check if the server supports sorting (RFC 5256).
        $esearch = $return_sort = $server_seq_sort = $server_sort = false;
        if (!empty($options['sort'])) {
            /* Make sure sort options are correct. If not, default to no
             * sort. */
            if (count(array_intersect($options['sort'], array_keys($sort_criteria))) === 0) {
                unset($options['sort']);
            } else {
                $return_sort = true;
                if ($this->_capability('SORT')) {
                    /* Make sure server supports DISPLAYFROM & DISPLAYTO. */
                    $server_sort = !array_intersect($options['sort'], array(Horde_Imap_Client::SORT_DISPLAYFROM, Horde_Imap_Client::SORT_DISPLAYTO)) || $this->_capability('SORT', 'DISPLAY');
                }
                /* If doing a sequence sort, need to do this on the client
                 * side. */
                if ($server_sort && in_array(Horde_Imap_Client::SORT_SEQUENCE, $options['sort'])) {
                    $server_sort = false;
                    /* Optimization: If doing only a sequence sort, just do a
                     * simple search and sort UIDs/sequences on client side. */
                    switch (count($options['sort'])) {
                        case 1:
                            $server_seq_sort = true;
                            break;
                        case 2:
                            $server_seq_sort = reset($options['sort']) == Horde_Imap_Client::SORT_REVERSE;
                            break;
                    }
                }
            }
        }
        $charset = is_null($options['_query']['charset']) ? 'US-ASCII' : $options['_query']['charset'];
        $partial = false;
        if ($server_sort) {
            $cmd = $this->_command(empty($options['sequence']) ? 'UID SORT' : 'SORT');
            $results = array();
            // Use ESEARCH (RFC 4466) response if server supports.
            $esearch = false;
            // Check for ESORT capability (RFC 5267)
            if ($this->_capability('ESORT')) {
                foreach ($options['results'] as $val) {
                    if (isset($results_criteria[$val]) && $val != Horde_Imap_Client::SEARCH_RESULTS_SAVE) {
                        $results[] = $results_criteria[$val];
                    }
                }
                $esearch = true;
            }
            // Add PARTIAL limiting (RFC 5267 [4.4])
            if ((!$esearch || !empty($options['partial'])) && $this->_capability('CONTEXT', 'SORT')) {
                /* RFC 5267 indicates RFC 4466 ESEARCH-like support,
                 * notwithstanding "real" RFC 4731 support. */
                $esearch = true;
                if (!empty($options['partial'])) {
                    /* Can't have both ALL and PARTIAL returns. */
                    $results = array_diff($results, array('ALL'));
                    $results[] = 'PARTIAL';
                    $results[] = $options['partial'];
                    $partial = true;
                }
            }
            if ($esearch && empty($this->_init['noesearch'])) {
                $cmd->add(array('RETURN', new Horde_Imap_Client_Data_Format_List($results)));
            }
            $tmp = new Horde_Imap_Client_Data_Format_List();
            foreach ($options['sort'] as $val) {
                if (isset($sort_criteria[$val])) {
                    $tmp->add($sort_criteria[$val]);
                }
            }
            $cmd->add($tmp);
            /* Charset is mandatory for SORT (RFC 5256 [3]).
             * However, if UTF-8 support is activated, a client MUST NOT
             * send the charset specification (RFC 6855 [3]; Errata 4029). */
            if (!$this->_capability()->isEnabled('UTF8=ACCEPT')) {
                $cmd->add($charset);
            }
        } else {
            $cmd = $this->_command(empty($options['sequence']) ? 'UID SEARCH' : 'SEARCH');
            $esearch = false;
            $results = array();
            // Check if the server supports ESEARCH (RFC 4731).
            if ($this->_capability('ESEARCH')) {
                foreach ($options['results'] as $val) {
                    if (isset($results_criteria[$val])) {
                        $results[] = $results_criteria[$val];
                    }
                }
                $esearch = true;
            }
            // Add PARTIAL limiting (RFC 5267 [4.4]).
            if ((!$esearch || !empty($options['partial'])) && $this->_capability('CONTEXT', 'SEARCH')) {
                /* RFC 5267 indicates RFC 4466 ESEARCH-like support,
                 * notwithstanding "real" RFC 4731 support. */
                $esearch = true;
                if (!empty($options['partial'])) {
                    // Can't have both ALL and PARTIAL returns.
                    $results = array_diff($results, array('ALL'));
                    $results[] = 'PARTIAL';
                    $results[] = $options['partial'];
                    $partial = true;
                }
            }
            if ($esearch && empty($this->_init['noesearch'])) {
                // Always use ESEARCH if available because it returns results
                // in a more compact sequence-set list
                $cmd->add(array('RETURN', new Horde_Imap_Client_Data_Format_List($results)));
            }
            /* Charset is optional for SEARCH (RFC 3501 [6.4.4]).
             * If UTF-8 support is activated, a client MUST NOT
             * send the charset specification (RFC 6855 [3]; Errata 4029). */
            if ($charset != 'US-ASCII' && !$this->_capability()->isEnabled('UTF8=ACCEPT')) {
                $cmd->add(array('CHARSET', $options['_query']['charset']));
            }
        }
        $cmd->add($options['_query']['query'], true);
        $pipeline = $this->_pipeline($cmd);
        $pipeline->data['esearchresp'] = array();
        $er =& $pipeline->data['esearchresp'];
        $pipeline->data['searchresp'] = $this->getIdsOb(array(), !empty($options['sequence']));
        $sr =& $pipeline->data['searchresp'];
        try {
            $resp = $this->_sendCmd($pipeline);
        } catch (Horde_Imap_Client_Exception $e) {
            if ($e instanceof Horde_Imap_Client_Exception_ServerResponse && $e->status === Horde_Imap_Client_Interaction_Server::NO && $charset != 'US-ASCII') {
                /* RFC 3501 [6.4.4]: BADCHARSET response code is only a
                 * SHOULD return. If it doesn't exist, need to check for
                 * command status of 'NO'. List of supported charsets in
                 * the BADCHARSET response has already been parsed and stored
                 * at this point. */
                $this->search_charset->setValid($charset, false);
                $e->setCode(Horde_Imap_Client_Exception::BADCHARSET);
            }
            if (empty($this->_temp['search_retry'])) {
                $this->_temp['search_retry'] = true;
                /* Bug #9842: Workaround broken Cyrus servers (as of
                 * 2.4.7). */
                if ($esearch && $charset != 'US-ASCII') {
                    $this->_capability()->remove('ESEARCH');
                    $this->_setInit('noesearch', true);
                    try {
                        return $this->_search($query, $options);
                    } catch (Horde_Imap_Client_Exception $e) {
                    }
                }
                /* Try to convert charset. */
                if ($e->getCode() === Horde_Imap_Client_Exception::BADCHARSET && $charset != 'US-ASCII') {
                    foreach ($this->search_charset->charsets as $val) {
                        $this->_temp['search_retry'] = 1;
                        $new_query = clone $query;
                        try {
                            $new_query->charset($val);
                            $options['_query'] = $new_query->build($this);
                            return $this->_search($new_query, $options);
                        } catch (Horde_Imap_Client_Exception $e) {
                        }
                    }
                }
                unset($this->_temp['search_retry']);
            }
            throw $e;
        }
        if ($return_sort && !$server_sort) {
            if ($server_seq_sort) {
                $sr->sort();
                if (reset($options['sort']) == Horde_Imap_Client::SORT_REVERSE) {
                    $sr->reverse();
                }
            } else {
                if (!isset($this->_temp['clientsort'])) {
                    $this->_temp['clientsort'] = new Horde_Imap_Client_Socket_ClientSort($this);
                }
                $sr = $this->getIdsOb($this->_temp['clientsort']->clientSort($sr, $options), !empty($options['sequence']));
            }
        }
        if (!$partial && !empty($options['partial'])) {
            $partial = $this->getIdsOb($options['partial'], true);
            $min = $partial->min - 1;
            $sr->sort();
            $sr = $this->getIdsOb(array_slice($sr->ids, $min, $partial->max - $min), !empty($options['sequence']));
        }
        $ret = array();
        foreach ($options['results'] as $val) {
            switch ($val) {
                case Horde_Imap_Client::SEARCH_RESULTS_COUNT:
                    $ret['count'] = $esearch && !$partial ? $er['count'] : count($sr);
                    break;
                case Horde_Imap_Client::SEARCH_RESULTS_MATCH:
                    $ret['match'] = $sr;
                    break;
                case Horde_Imap_Client::SEARCH_RESULTS_MAX:
                    $ret['max'] = $esearch ? !$partial && isset($er['max']) ? $er['max'] : null : (count($sr) ? max($sr->ids) : null);
                    break;
                case Horde_Imap_Client::SEARCH_RESULTS_MIN:
                    $ret['min'] = $esearch ? !$partial && isset($er['min']) ? $er['min'] : null : (count($sr) ? min($sr->ids) : null);
                    break;
                case Horde_Imap_Client::SEARCH_RESULTS_RELEVANCY:
                    $ret['relevancy'] = $esearch && isset($er['relevancy']) ? $er['relevancy'] : array();
                    break;
                case Horde_Imap_Client::SEARCH_RESULTS_SAVE:
                    $this->_temp['search_save'] = $ret['save'] = $esearch ? empty($resp->data['searchnotsaved']) : false;
                    break;
            }
        }
        // Add modseq data, if needed.
        if (!empty($er['modseq'])) {
            $ret['modseq'] = $er['modseq'];
        }
        unset($this->_temp['search_retry']);
        /* Check for EXPUNGEISSUED (RFC 2180 [4.3]/RFC 5530 [3]). */
        if (!empty($resp->data['expungeissued'])) {
            $this->noop();
        }
        return $ret;
    }