Horde_Imap_Client_Socket::_parseFetch PHP Method

_parseFetch() protected method

the flags change).
protected _parseFetch ( Horde_Imap_Client_Interaction_Pipeline $pipeline, integer $id, Horde_Imap_Client_Tokenize $data )
$pipeline Horde_Imap_Client_Interaction_Pipeline Pipeline object.
$id integer The message sequence number.
$data Horde_Imap_Client_Tokenize The server response.
    protected function _parseFetch(Horde_Imap_Client_Interaction_Pipeline $pipeline, $id, Horde_Imap_Client_Tokenize $data)
    {
        if ($data->next() !== true) {
            return;
        }
        $ob = $pipeline->fetch->get($id);
        $ob->setSeq($id);
        $flags = $modseq = $uid = false;
        while (($tag = $data->next()) !== false) {
            $tag = Horde_String::upper($tag);
            /* Catch equivalent RFC822 tags, in case server returns them
             * (in error, since we only use BODY in FETCH requests). */
            switch ($tag) {
                case 'RFC822':
                    $tag = 'BODY[]';
                    break;
                case 'RFC822.HEADER':
                    $tag = 'BODY[HEADER]';
                    break;
                case 'RFC822.TEXT':
                    $tag = 'BODY[TEXT]';
                    break;
            }
            switch ($tag) {
                case 'BODYSTRUCTURE':
                    $data->next();
                    $structure = $this->_parseBodystructure($data);
                    $structure->buildMimeIds();
                    $ob->setStructure($structure);
                    break;
                case 'ENVELOPE':
                    $data->next();
                    $ob->setEnvelope($this->_parseEnvelope($data));
                    break;
                case 'FLAGS':
                    $data->next();
                    $ob->setFlags($data->flushIterator());
                    $flags = true;
                    break;
                case 'INTERNALDATE':
                    $ob->setImapDate($data->next());
                    break;
                case 'RFC822.SIZE':
                    $ob->setSize($data->next());
                    break;
                case 'UID':
                    $ob->setUid($data->next());
                    $uid = true;
                    break;
                case 'MODSEQ':
                    $data->next();
                    $modseq = $data->next();
                    $data->next();
                    /* MODSEQ must be greater than 0, so do sanity checking. */
                    if ($modseq > 0) {
                        $ob->setModSeq($modseq);
                        /* Store MODSEQ value. It may be used as the highestmodseq
                         * once a tagged response is received (RFC 7162 [6]). */
                        $pipeline->data['modseqs'][] = $modseq;
                    }
                    break;
                default:
                    // Catch BODY[*]<#> responses
                    if (strpos($tag, 'BODY[') === 0) {
                        // Remove the beginning 'BODY['
                        $tag = substr($tag, 5);
                        // BODY[HEADER.FIELDS] request
                        if (!empty($pipeline->data['fetch_lookup']) && strpos($tag, 'HEADER.FIELDS') !== false) {
                            $data->next();
                            $sig = $tag . ' (' . implode(' ', array_map('Horde_String::upper', $data->flushIterator())) . ')';
                            // Ignore the trailing bracket
                            $data->next();
                            $ob->setHeaders($pipeline->data['fetch_lookup'][$sig], $data->next());
                        } else {
                            // Remove trailing bracket and octet start info
                            $tag = substr($tag, 0, strrpos($tag, ']'));
                            if (!strlen($tag)) {
                                // BODY[] request
                                if (!is_null($tmp = $data->nextStream())) {
                                    $ob->setFullMsg($tmp);
                                }
                            } elseif (is_numeric(substr($tag, -1))) {
                                // BODY[MIMEID] request
                                if (!is_null($tmp = $data->nextStream())) {
                                    $ob->setBodyPart($tag, $tmp);
                                }
                            } else {
                                // BODY[HEADER|TEXT|MIME] request
                                if (($last_dot = strrpos($tag, '.')) === false) {
                                    $mime_id = 0;
                                } else {
                                    $mime_id = substr($tag, 0, $last_dot);
                                    $tag = substr($tag, $last_dot + 1);
                                }
                                if (!is_null($tmp = $data->nextStream())) {
                                    switch ($tag) {
                                        case 'HEADER':
                                            $ob->setHeaderText($mime_id, $tmp);
                                            break;
                                        case 'TEXT':
                                            $ob->setBodyText($mime_id, $tmp);
                                            break;
                                        case 'MIME':
                                            $ob->setMimeHeader($mime_id, $tmp);
                                            break;
                                    }
                                }
                            }
                        }
                    } elseif (strpos($tag, 'BINARY[') === 0) {
                        // Catch BINARY[*]<#> responses
                        // Remove the beginning 'BINARY[' and the trailing bracket
                        // and octet start info
                        $tag = substr($tag, 7, strrpos($tag, ']') - 7);
                        $body = $data->nextStream();
                        if (is_null($body)) {
                            /* Dovecot bug (as of 2.2.12): binary fetch of body
                             * part may fail with NIL return if decoding failed on
                             * server. Try again with non-decoded body. */
                            $bq = $pipeline->data['binaryquery'][$tag];
                            unset($bq['decode']);
                            $query = new Horde_Imap_Client_Fetch_Query();
                            $query->bodyPart($tag, $bq);
                            $qids = ($quid = $ob->getUid()) ? new Horde_Imap_Client_Ids($quid) : new Horde_Imap_Client_Ids($id, true);
                            $pipeline->data['fetch_followup'][] = array('_query' => $query, 'ids' => $qids);
                        } else {
                            $ob->setBodyPart($tag, $body, empty($this->_temp['literal8']) ? '8bit' : 'binary');
                        }
                    } elseif (strpos($tag, 'BINARY.SIZE[') === 0) {
                        // Catch BINARY.SIZE[*] responses
                        // Remove the beginning 'BINARY.SIZE[' and the trailing
                        // bracket and octet start info
                        $tag = substr($tag, 12, strrpos($tag, ']') - 12);
                        $ob->setBodyPartSize($tag, $data->next());
                    }
                    break;
            }
        }
        /* MODSEQ issue: Oh joy. Per RFC 5162 (see Errata #1807), FETCH FLAGS
         * responses are NOT required to provide UID information, even if
         * QRESYNC is explicitly enabled. Caveat: the FLAGS information
         * returned during a SELECT/EXAMINE MUST contain UIDs so we are OK
         * there.
         * The good news: all decent IMAP servers (Cyrus, Dovecot) will always
         * provide UID information, so this is not normally an issue.
         * The bad news: spec-wise, this behavior cannot be 100% guaranteed.
         * Compromise: We will watch for a FLAGS response with a MODSEQ and
         * check if a UID exists also. If not, put the sequence number in a
         * queue - it is possible the UID information may appear later in an
         * untagged response. When the command is over, double check to make
         * sure there are none of these MODSEQ/FLAGS that are still UID-less.
         * In the (rare) event that there is, don't cache anything and
         * immediately close the mailbox: flags will be correctly sync'd next
         * mailbox open so we only lose a bit of caching efficiency.
         * Otherwise, we could end up with an inconsistent cached state.
         * This Errata has been fixed in 7162 [3.2.4]. */
        if ($flags && $modseq && !$uid) {
            $pipeline->data['modseqs_nouid'][] = $id;
        }
    }