Parse individual part of the structure

@param  resource $stream
@param  int $uid
@param  stdClass $part
@param  int $partNo
@return stdClass | null
540359
protected function parsePart($stream, $uid, $part, $partNo = 1)
    {
        if (!in_array($part->type, [TYPETEXT, TYPEMULTIPART])) {
            return null;
        }

        $body = imap_fetchbody($stream, $uid, $partNo, static::$bodyFlags);

        $body = static::decode($body, $part->encoding);
        if ('' !== ($charset = $this->findCharset($part))) {
            $body = static::convertBodyEncoding($body, $charset, $part->encoding);
        }

        return (object) [
            'body' => $body,
            'mime_type' => strtolower($part->subtype)
        ];
    }
1103212
private static function isAttachment(\stdClass $part): bool
    {
        if (isset(self::$typesMap[$part->type]) && self::TYPE_MULTIPART === self::$typesMap[$part->type]) {
            return false;
        }

        // Attachment with correct Content-Disposition header
        if ($part->ifdisposition) {
            if ('attachment' === \strtolower($part->disposition)) {
                return true;
            }

            if (
                    'inline' === \strtolower($part->disposition)
                && self::SUBTYPE_PLAIN !== \strtoupper($part->subtype)
                && self::SUBTYPE_HTML !== \strtoupper($part->subtype)
            ) {
                return true;
            }
        }

        // Attachment without Content-Disposition header
        if ($part->ifparameters) {
            foreach ($part->parameters as $parameter) {
                if (isset(self::$attachmentKeys[\strtolower($parameter->attribute)])) {
                    return true;
                }
            }
        }

        /*
        if ($part->ifdparameters) {
            foreach ($part->dparameters as $parameter) {
                if (isset(self::$attachmentKeys[\strtolower($parameter->attribute)])) {
                    return true;
                }
            }
        }
         */

        if (self::SUBTYPE_RFC822 === \strtoupper($part->subtype)) {
            return true;
        }

        return false;
    }
396361
public function getPart($partNumber, $encoding)
    {
        $data = imap_fetchbody($this->conn, $this->messageNumber, $partNumber);
        switch ($encoding) {
            case 0:
                return $data; // 7BIT
            case 1:
                return $data; // 8BIT
            case 2:
                return $data; // BINARY
            case 3:
                return base64_decode($data); // BASE64
            case 4:
                return quoted_printable_decode($data); // QUOTED_PRINTABLE
            case 5:
                return $data; // OTHER
        }
    }
651158
public function parseCondition(Stream $stream)
    {
        $expr = $this->parseExpr($stream);

        $stream->expects(Token::TYPE_KEYWORD, 'is');

        if ($stream->current()->equals(Token::TYPE_KEYWORD, 'not')) {
            $stream->expects(Token::TYPE_KEYWORD, 'not');

            $not = true;
        } else {
            $not = false;
        }

        if ($stream->current()->equals(Token::TYPE_KEYWORD, 'like')) {
            $stream->expects(Token::TYPE_KEYWORD, 'like');
        }

        $expr = new EqualsNode($expr, $this->parseExpr($stream));

        if ($not === true) {
            $expr = new UnaryPrefixOperatorNode('!', new GroupNode($expr));
        }

        if ($stream->current()->equals(Token::TYPE_KEYWORD, 'and')) {
            $stream->expects(Token::TYPE_KEYWORD, 'and');

            $expr = new BinaryInfixOperatorNode('&&', $expr, $this->parseCondition($stream));
        }

        if ($stream->current()->equals(Token::TYPE_KEYWORD, 'or')) {
            $stream->expects(Token::TYPE_KEYWORD, 'or');

            $expr = new BinaryInfixOperatorNode('||', $expr, $this->parseCondition($stream));
        }

        return $expr;
    }
801237
public function resolve($part, $source)
    {
        if (is_array($source)) {
            $source = $this->handleArray($part, $source);
        } elseif (is_object($source)) {
            $source = $this->handleObject($part, $source);
        }

        return $source;
    }
1014470
private function parseClass(Stream $stream)
    {
        $stream->expects(Token::TYPE_KEYWORD, 'new');

        $class = [$stream->expects(Token::TYPE_IDENTIFIER)->getValue()];

        while ($stream->current()->equals(Token::TYPE_SYMBOL, '\\')) {
            $stream->expects(Token::TYPE_SYMBOL, '\\');

            $class[] = $stream->expects(Token::TYPE_IDENTIFIER)->getValue();
        }

        $class = implode('\\', $class);

        $arguments = [];

        if ($stream->current()->equals(Token::TYPE_SYMBOL, '(')) {
            $stream->expects(Token::TYPE_SYMBOL, '(');

            if (!$stream->current()->equals(Token::TYPE_SYMBOL, ')')) {
                $arguments = $this->parseList($stream);
            }

            $stream->expects(Token::TYPE_SYMBOL, ')');
        }

        return new ClassNode($class, $arguments);
    }
1187253
public function getPart($part)
    {
        $part = strtolower($part);
        if (!array_key_exists($part, $this->_parts)) {
            // require_once 'Zend/Db/Select/Exception.php';
            throw new Zend_Db_Select_Exception("Invalid Select part '$part'");
        }
        return $this->_parts[$part];
    }
667105
protected function parseMailHeader($stream, $uid)
    {
        $header = imap_headerinfo($stream, imap_msgno($stream, $uid));

        return [
            'msgNo' => (int) $header->Msgno,
            'subject' => $this->parseSubject($header->subject),
            'date' => $header->udate,
            'to' => isset($header->to)
                ? $this->parseAddress($header->to) : null,
            'cc' => isset($header->cc)
                ? $this->parseAddress($header->cc) : null,
            'bcc' => isset($header->bcc)
                ? $this->parseAddress($header->bcc) : null,
            'sender' => isset($header->sender)
                ? $this->parseAddress($header->sender) : null,
            'from' => isset($header->from)
                ? $this->parseAddress($header->from) : null,
            'replyTo' => isset($header->reply_to)
                ? $this->parseAddress($header->reply_to) : null,
            'recent' => $this->parseFlag('R', $header->Recent),
            'unseen' => $this->parseFlag('U', $header->Unseen),
            'flagged' => $this->parseFlag('F', $header->Flagged),
            'answered' => $this->parseFlag('A', $header->Answered),
            'deleted' => $this->parseFlag('D', $header->Deleted),
            'draft' => $this->parseFlag('X', $header->Draft)
        ];
    }
555577
protected function structure_part($part, $count = 0, $parent = '', $mime_headers = null)
    {
        $struct = new rcube_message_part;
        $struct->mime_id = empty($parent) ? (string)$count : "$parent.$count";

        // multipart
        if (is_array($part[0])) {
            $struct->ctype_primary = 'multipart';

        /* RFC3501: BODYSTRUCTURE fields of multipart part
            part1 array
            part2 array
            part3 array
            ....
            1. subtype
            2. parameters (optional)
            3. description (optional)
            4. language (optional)
            5. location (optional)
        */

            // find first non-array entry
            for ($i=1; $i<count($part); $i++) {
                if (!is_array($part[$i])) {
                    $struct->ctype_secondary = strtolower($part[$i]);

                    // read content type parameters
                    if (is_array($part[$i+1])) {
                        $struct->ctype_parameters = array();
                        for ($j=0; $j<count($part[$i+1]); $j+=2) {
                            $param = strtolower($part[$i+1][$j]);
                            $struct->ctype_parameters[$param] = $part[$i+1][$j+1];
                        }
                    }

                    break;
                }
            }

            $struct->mimetype = 'multipart/'.$struct->ctype_secondary;

            // build parts list for headers pre-fetching
            for ($i=0; $i<count($part); $i++) {
                if (!is_array($part[$i])) {
                    break;
                }
                // fetch message headers if message/rfc822
                // or named part (could contain Content-Location header)
                if (!is_array($part[$i][0])) {
                    $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
                    if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
                        $mime_part_headers[] = $tmp_part_id;
                    }
                    else if (in_array('name', (array)$part[$i][2]) && empty($part[$i][3])) {
                        $mime_part_headers[] = $tmp_part_id;
                    }
                }
            }

            // pre-fetch headers of all parts (in one command for better performance)
            // @TODO: we could do this before _structure_part() call, to fetch
            // headers for parts on all levels
            if ($mime_part_headers) {
                $mime_part_headers = $this->conn->fetchMIMEHeaders($this->folder,
                    $this->msg_uid, $mime_part_headers);
            }

            $struct->parts = array();
            for ($i=0, $count=0; $i<count($part); $i++) {
                if (!is_array($part[$i])) {
                    break;
                }
                $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
                $struct->parts[] = $this->structure_part($part[$i], ++$count, $struct->mime_id,
                    $mime_part_headers[$tmp_part_id]);
            }

            return $struct;
        }

        /* RFC3501: BODYSTRUCTURE fields of non-multipart part
            0. type
            1. subtype
            2. parameters
            3. id
            4. description
            5. encoding
            6. size
          -- text
            7. lines
          -- message/rfc822
            7. envelope structure
            8. body structure
            9. lines
          --
            x. md5 (optional)
            x. disposition (optional)
            x. language (optional)
            x. location (optional)
        */

        // regular part
        $struct->ctype_primary = strtolower($part[0]);
        $struct->ctype_secondary = strtolower($part[1]);
        $struct->mimetype = $struct->ctype_primary.'/'.$struct->ctype_secondary;

        // read content type parameters
        if (is_array($part[2])) {
            $struct->ctype_parameters = array();
            for ($i=0; $i<count($part[2]); $i+=2) {
                $struct->ctype_parameters[strtolower($part[2][$i])] = $part[2][$i+1];
            }

            if (isset($struct->ctype_parameters['charset'])) {
                $struct->charset = $struct->ctype_parameters['charset'];
            }
        }

        // #1487700: workaround for lack of charset in malformed structure
        if (empty($struct->charset) && !empty($mime_headers) && $mime_headers->charset) {
            $struct->charset = $mime_headers->charset;
        }

        // read content encoding
        if (!empty($part[5])) {
            $struct->encoding = strtolower($part[5]);
            $struct->headers['content-transfer-encoding'] = $struct->encoding;
        }

        // get part size
        if (!empty($part[6])) {
            $struct->size = intval($part[6]);
        }

        // read part disposition
        $di = 8;
        if ($struct->ctype_primary == 'text') {
            $di += 1;
        }
        else if ($struct->mimetype == 'message/rfc822') {
            $di += 3;
        }

        if (is_array($part[$di]) && count($part[$di]) == 2) {
            $struct->disposition = strtolower($part[$di][0]);
            if ($struct->disposition && $struct->disposition !== 'inline' && $struct->disposition !== 'attachment') {
                // RFC2183, Section 2.8 - unrecognized type should be treated as "attachment"
                $struct->disposition = 'attachment';
            }
            if (is_array($part[$di][1])) {
                for ($n=0; $n<count($part[$di][1]); $n+=2) {
                    $struct->d_parameters[strtolower($part[$di][1][$n])] = $part[$di][1][$n+1];
                }
            }
        }

        // get message/rfc822's child-parts
        if (is_array($part[8]) && $di != 8) {
            $struct->parts = array();
            for ($i=0, $count=0; $i<count($part[8]); $i++) {
                if (!is_array($part[8][$i])) {
                    break;
                }
                $struct->parts[] = $this->structure_part($part[8][$i], ++$count, $struct->mime_id);
            }
        }

        // get part ID
        if (!empty($part[3])) {
            $struct->content_id = $part[3];
            $struct->headers['content-id'] = $part[3];

            if (empty($struct->disposition)) {
                $struct->disposition = 'inline';
            }
        }

        // fetch message headers if message/rfc822 or named part (could contain Content-Location header)
        if ($struct->ctype_primary == 'message' || ($struct->ctype_parameters['name'] && !$struct->content_id)) {
            if (empty($mime_headers)) {
                $mime_headers = $this->conn->fetchPartHeader(
                    $this->folder, $this->msg_uid, true, $struct->mime_id);
            }

            if (is_string($mime_headers)) {
                $struct->headers = rcube_mime::parse_headers($mime_headers) + $struct->headers;
            }
            else if (is_object($mime_headers)) {
                $struct->headers = get_object_vars($mime_headers) + $struct->headers;
            }

            // get real content-type of message/rfc822
            if ($struct->mimetype == 'message/rfc822') {
                // single-part
                if (!is_array($part[8][0])) {
                    $struct->real_mimetype = strtolower($part[8][0] . '/' . $part[8][1]);
                }
                // multi-part
                else {
                    for ($n=0; $n<count($part[8]); $n++) {
                        if (!is_array($part[8][$n])) {
                            break;
                        }
                    }
                    $struct->real_mimetype = 'multipart/' . strtolower($part[8][$n]);
                }
            }

            if ($struct->ctype_primary == 'message' && empty($struct->parts)) {
                if (is_array($part[8]) && $di != 8) {
                    $struct->parts[] = $this->structure_part($part[8], ++$count, $struct->mime_id);
                }
            }
        }

        // normalize filename property
        $this->set_part_filename($struct, $mime_headers);

        return $struct;
    }
179718
public function parse(TokenStream $stream) : RootNode
    {
        if (! $this->runtime) {
            throw new AegisError('Runtime needs to be set before parsing');
        }

        $this->prepare($stream);
        $this->parseOutsideTag();

        if ($this->cursor !== $this->lastTokenIndex) {
            $this->syntaxError('Unexpected token ' . $this->getCurrentToken());
        }

        return $this->getRoot();
    }
162580
private function find_part_id($part_id, $data)
    {
        $ids   = explode('.', $part_id);
        $i     = 0;
        $count = count($ids);

        while ($i < $count && strlen($part = implode('.', array_slice($ids, 0, ++$i)))) {
            if (array_key_exists($part, $data)) {
                return $part;
            }
        }
    }
1296940
public void processStreamPartByPart(String delimiterPattern, Function<String, Object> function) {
        StreamUtil.partByPart(dataToType(InputStream.class), delimiterPattern, function);
    }
464626
protected function partIdIsChildOfPart($partId, $parentPartId)
    {
        $parentPartId = $parentPartId.'.';
        return substr($partId, 0, strlen($parentPartId)) == $parentPartId;
    }
316660
public function parseExpr(Stream $stream)
    {
        if ($stream->current()->is(Token::TYPE_STRING | Token::TYPE_SINGLE_QUOTED)) {
            return new ValueFragmentNode($stream->expects(Token::TYPE_STRING | Token::TYPE_SINGLE_QUOTED)->getValue(), 'varchar');
        }

        if ($stream->current()->is(Token::TYPE_STRING | Token::TYPE_DOUBLE_QUOTED)) {
            return new FragmentNode($stream->expects(Token::TYPE_STRING | Token::TYPE_DOUBLE_QUOTED)->getValue());
        }

        if ($stream->current()->is(Token::TYPE_NUMBER)) {
            $value = $stream->expects(Token::TYPE_NUMBER)->getValue();

            return new ValueFragmentNode($value, strpos($value, '.') === false ? 'int8' : 'decimal');
        }

        if ($stream->current()->is(Token::TYPE_CONSTANT)) {
            $value = strtolower($stream->expects(Token::TYPE_CONSTANT)->getValue());

            return new ValueFragmentNode($value, in_array($value, ['true', 'false']) ? 'bool' : null);
        }

        if ($stream->current()->is(Token::TYPE_IDENTIFIER) && $stream->peek()->equals(Token::TYPE_SYMBOL, '(')) {
            $func = $stream->expects(Token::TYPE_IDENTIFIER)->getValue();
            $args = [];

            $stream->expects(Token::TYPE_SYMBOL, '(');

            if (!$stream->current()->equals(Token::TYPE_SYMBOL, ')')) {
                do {
                    $args[] = $this->parseExpr($stream);
                } while ($stream->current()->equals(Token::TYPE_SYMBOL, ',') && $stream->expects(Token::TYPE_SYMBOL, ','));
            }

            $func = new FuncNode($func, $args);

            $stream->expects(Token::TYPE_SYMBOL, ')');

            return $func;
        }

        if ($stream->current()->is(Token::TYPE_IDENTIFIER)) {
            $path = [$stream->expects(Token::TYPE_IDENTIFIER)->getValue()];

            while ($stream->hasNext() && $stream->current()->equals(Token::TYPE_SYMBOL, '.')) {
                $stream->expects(Token::TYPE_SYMBOL, '.');

                $path[] = $stream->expects(Token::TYPE_IDENTIFIER)->getValue();
            }

            return new ReferenceNode($path);
        }

        if ($stream->current()->equals(Token::TYPE_SYMBOL, '{')) {
            $stream->expects(Token::TYPE_SYMBOL, '{');

            $hash = [];

            if (!$stream->current()->equals(Token::TYPE_SYMBOL, '}')) {
                do {
                    $key = $stream->expects(Token::TYPE_IDENTIFIER)->getValue();

                    $stream->expects(Token::TYPE_SYMBOL, ':');

                    $value = $this->parseExpr($stream);

                    $hash[$key] = $value;
                } while ($stream->current()->equals(Token::TYPE_SYMBOL, ',') && $stream->expects(Token::TYPE_SYMBOL, ','));
            }

            $stream->expects(Token::TYPE_SYMBOL, '}');

            return new RowFragmentNode($hash);
        }

        if ($stream->current()->equals(Token::TYPE_SYMBOL, '[')) {
            $stream->expects(Token::TYPE_SYMBOL, '[');

            $array = [];

            if (!$stream->current()->equals(Token::TYPE_SYMBOL, ']')) {
                do {
                    $array[] = $this->parseExpr($stream);
                } while ($stream->current()->equals(Token::TYPE_SYMBOL, ',') && $stream->expects(Token::TYPE_SYMBOL, ','));
            }

            $stream->expects(Token::TYPE_SYMBOL, ']');

            return new SetFragmentNode($array);
        }

        throw new \Exception(sprintf(
            'Fails to parse stream "%s". Unexpected token %s at line %d.',
            $stream->humanize(),
            Token::humanize($stream->current()->getType()),
            $stream->current()->getLine()
        ));
    }
416804
public function get_raw_body($uid, $fp=null, $part = null)
    {
        if (!$this->check_connection()) {
            return null;
        }

        return $this->conn->handlePartBody($this->folder, $uid,
            true, $part, null, false, $fp);
    }
1002696
public function getLemmas($word, $partOfSpeech = null) {
    if($partOfSpeech !== null && !isset(self::$partsOfSpeech[$partOfSpeech])) {
      $posAsString = implode(' or ', array_keys(self::$partsOfSpeech));
      throw new InvalidArgumentException("partsOfSpeech must be {$posAsString}.");
    }

    $wordEntity = new Word($word);
    if($partOfSpeech !== null) {
      $pos = $this->getPos($partOfSpeech);
      $lemmas = $this->getBaseForm($wordEntity, $pos);
      if(!$lemmas) {
        $lemmas[] = new Lemma($word, $partOfSpeech);
      }
    } else {
      $lemmas = [];
      /** @var PartOfSpeech $pos */
      foreach(self::$partsOfSpeech as $pos) {
        $lemmas = array_merge($lemmas, $this->getBaseForm($wordEntity, $pos));
      }

      if(!$lemmas) {
        /** @var PartOfSpeech $pos */
        foreach(self::$partsOfSpeech as $pos) {
          if(isset($pos->getWordsList()[$word])) {
            $lemmas[] = new Lemma($word, $pos->getPartOfSpeechAsString());
          }
        }
      }

      if(!$lemmas) {
        $lemmas[] = new Lemma($word);
      }
    }

    return array_unique($lemmas, SORT_REGULAR);
  }
969972
public function get_raw_headers($uid, $part = null)
    {
        if (!$this->check_connection()) {
            return null;
        }

        return $this->conn->fetchPartHeader($this->folder, $uid, true, $part);
    }